The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
Changes 07
MANIFEST 846
MANIFEST.SKIP 11
META.yml 311
Makefile.PL 23
README 5158
inc/Module/AutoInstall.pm 217
inc/Module/Install/AuthorRequires.pm 038
inc/Module/Install/AuthorTests.pm 059
inc/Module/Install/AutoInstall.pm 223
inc/Module/Install/Base.pm 38
inc/Module/Install/Can.pm 11
inc/Module/Install/Catalyst.pm 2560
inc/Module/Install/External.pm 11
inc/Module/Install/Fetch.pm 11
inc/Module/Install/Include.pm 11
inc/Module/Install/Makefile.pm 41188
inc/Module/Install/Metadata.pm 88179
inc/Module/Install/Scripts.pm 11
inc/Module/Install/Win32.pm 11
inc/Module/Install/WriteAll.pm 25
inc/Module/Install.pm 89129
lib/Gitalist/Controller/Fragment/Ref.pm 117
lib/Gitalist/Git/CollectionOfRepositories/FromDirectoryRecursive.pm 079
lib/Gitalist/Git/CollectionOfRepositories.pm 12
lib/Gitalist/Git/Head.pm 057
lib/Gitalist/Git/Object/Commit.pm 021
lib/Gitalist/Git/Object.pm 15
lib/Gitalist/Git/Repository.pm 6412
lib/Gitalist/Git/Tag.pm 079
lib/Gitalist/Model/CollectionOfRepos.pm 22
lib/Gitalist/URIStructure/Ref.pm 914
lib/Gitalist.pm 5160
root/favicon_gif.ico --
t/01app.t 11
t/02git_CollectionOfRepositories_FromDirectory.t 11
t/02git_CollectionOfRepositories_FromDirectoryRecursive.t 055
t/02git_Repository.t 1411
t/02git_head.t 035
t/02git_object.t 13
t/02git_tag.t 036
t/02git_util.t 11
t/03legacy_uri.t 11
t/app-mech-rootpage.t 11
t/atom.t 11
t/author/notabs.t 07
t/author/pod.t 19
t/author/podcoverage.t 310
t/lib/repositories/recursive/barerecursive.git/HEAD 01
t/lib/repositories/recursive/barerecursive.git/config 07
t/lib/repositories/recursive/barerecursive.git/description 01
t/lib/repositories/recursive/barerecursive.git/hooks/applypatch-msg.sample 015
t/lib/repositories/recursive/barerecursive.git/hooks/commit-msg.sample 024
t/lib/repositories/recursive/barerecursive.git/hooks/post-commit.sample 08
t/lib/repositories/recursive/barerecursive.git/hooks/post-receive.sample 015
t/lib/repositories/recursive/barerecursive.git/hooks/post-update.sample 08
t/lib/repositories/recursive/barerecursive.git/hooks/pre-applypatch.sample 014
t/lib/repositories/recursive/barerecursive.git/hooks/pre-commit.sample 046
t/lib/repositories/recursive/barerecursive.git/hooks/pre-rebase.sample 0169
t/lib/repositories/recursive/barerecursive.git/hooks/prepare-commit-msg.sample 036
t/lib/repositories/recursive/barerecursive.git/hooks/update.sample 0128
t/lib/repositories/recursive/barerecursive.git/info/exclude 06
t/lib/repositories/recursive/goingdeeper/scratch.git/HEAD 01
t/lib/repositories/recursive/goingdeeper/scratch.git/config 07
t/lib/repositories/recursive/goingdeeper/scratch.git/description 01
t/lib/repositories/recursive/goingdeeper/scratch.git/hooks/applypatch-msg.sample 015
t/lib/repositories/recursive/goingdeeper/scratch.git/hooks/commit-msg.sample 024
t/lib/repositories/recursive/goingdeeper/scratch.git/hooks/post-commit.sample 08
t/lib/repositories/recursive/goingdeeper/scratch.git/hooks/post-receive.sample 015
t/lib/repositories/recursive/goingdeeper/scratch.git/hooks/post-update.sample 08
t/lib/repositories/recursive/goingdeeper/scratch.git/hooks/pre-applypatch.sample 014
t/lib/repositories/recursive/goingdeeper/scratch.git/hooks/pre-commit.sample 046
t/lib/repositories/recursive/goingdeeper/scratch.git/hooks/pre-rebase.sample 0169
t/lib/repositories/recursive/goingdeeper/scratch.git/hooks/prepare-commit-msg.sample 036
t/lib/repositories/recursive/goingdeeper/scratch.git/hooks/update.sample 0128
t/lib/repositories/recursive/goingdeeper/scratch.git/info/exclude 06
t/lib/repositories/recursive/nothinginhere/emptyfile 00
t/model_collectionofrepos.t 22
t/opml.t 11
t/rss.t 11
t/scripts.t 11
t/view_Default.t 11
82 files changed (This is a version diff) 4932310
@@ -1,5 +1,12 @@
 This file documents the revision history for Perl extension Gitalist.
 
+0.002007 2011-02-19
+   - Add support for recursively searching for git repos (Dipesh Patel)
+   - Cleaned up model code in Gitalist::Git:: (Zachary Stevens)
+   - Improve POD mark-up, some typos (Lars Dɪᴇᴄᴋᴏᴡ 迪拉斯)
+   - Regenerated README and fixed tests for bootstrapped checkouts.
+   - Add Test::Exception dep.
+
 0.002006 2010-10-17
    - Added notes regarding slash encoding in Catalyst
    - Fixed typo in core.css
@@ -1,20 +1,22 @@
 Changes
 gitalist.conf
 inc/File/Copy/Recursive.pm
+inc/Module/AutoInstall.pm
 inc/Module/Install.pm
-inc/Module/Install/WriteAll.pm
-inc/Module/Install/Include.pm
+inc/Module/Install/AuthorRequires.pm
+inc/Module/Install/AuthorTests.pm
+inc/Module/Install/AutoInstall.pm
 inc/Module/Install/Base.pm
-inc/Module/Install/Metadata.pm
 inc/Module/Install/Can.pm
-inc/Module/Install/Fetch.pm
-inc/Module/Install/External.pm
-inc/Module/Install/AutoInstall.pm
 inc/Module/Install/Catalyst.pm
+inc/Module/Install/External.pm
+inc/Module/Install/Fetch.pm
+inc/Module/Install/Include.pm
 inc/Module/Install/Makefile.pm
-inc/Module/Install/Win32.pm
+inc/Module/Install/Metadata.pm
 inc/Module/Install/Scripts.pm
-inc/Module/AutoInstall.pm
+inc/Module/Install/Win32.pm
+inc/Module/Install/WriteAll.pm
 lib/Gitalist.pm
 lib/Gitalist/ActionRole/FilenameArgs.pm
 lib/Gitalist/ContentMangler/Resolver.pm
@@ -32,8 +34,10 @@ lib/Gitalist/Controller/Root.pm
 lib/Gitalist/Faq.pod
 lib/Gitalist/Git/CollectionOfRepositories.pm
 lib/Gitalist/Git/CollectionOfRepositories/FromDirectory.pm
+lib/Gitalist/Git/CollectionOfRepositories/FromDirectoryRecursive.pm
 lib/Gitalist/Git/CollectionOfRepositories/FromListOfDirectories.pm
 lib/Gitalist/Git/HasUtils.pm
+lib/Gitalist/Git/Head.pm
 lib/Gitalist/Git/Object.pm
 lib/Gitalist/Git/Object/Blob.pm
 lib/Gitalist/Git/Object/Commit.pm
@@ -41,6 +45,7 @@ lib/Gitalist/Git/Object/HasTree.pm
 lib/Gitalist/Git/Object/Tag.pm
 lib/Gitalist/Git/Object/Tree.pm
 lib/Gitalist/Git/Repository.pm
+lib/Gitalist/Git/Tag.pm
 lib/Gitalist/Git/Types.pm
 lib/Gitalist/Git/Util.pm
 lib/Gitalist/Model/CollectionOfRepos.pm
@@ -68,6 +73,7 @@ root/_header_feeds.tt2
 root/_log_pager.tt2
 root/_refs.tt2
 root/favicon.ico
+root/favicon_gif.ico
 root/fragment/collectionofrepositories.tt2
 root/fragment/ref/blame.tt2
 root/fragment/ref/blob.tt2
@@ -159,8 +165,11 @@ script/gitalist_test.pl
 t/00git_version.t
 t/01app.t
 t/02git_CollectionOfRepositories_FromDirectory.t
+t/02git_CollectionOfRepositories_FromDirectoryRecursive.t
+t/02git_head.t
 t/02git_object.t
 t/02git_Repository.t
+t/02git_tag.t
 t/02git_util.t
 t/03legacy_uri.t
 t/app-mech-rootpage.t
@@ -207,6 +216,35 @@ t/lib/repositories/nodescription/objects/82/b5fee28277349b6d46beff5fdf6a7152347b
 t/lib/repositories/nodescription/objects/90/62594aebb5df0de7fb92413f17a9eced196c22
 t/lib/repositories/nodescription/objects/pack/.gitignore
 t/lib/repositories/nodescription/refs/heads/master
+t/lib/repositories/recursive/barerecursive.git/config
+t/lib/repositories/recursive/barerecursive.git/description
+t/lib/repositories/recursive/barerecursive.git/HEAD
+t/lib/repositories/recursive/barerecursive.git/hooks/applypatch-msg.sample
+t/lib/repositories/recursive/barerecursive.git/hooks/commit-msg.sample
+t/lib/repositories/recursive/barerecursive.git/hooks/post-commit.sample
+t/lib/repositories/recursive/barerecursive.git/hooks/post-receive.sample
+t/lib/repositories/recursive/barerecursive.git/hooks/post-update.sample
+t/lib/repositories/recursive/barerecursive.git/hooks/pre-applypatch.sample
+t/lib/repositories/recursive/barerecursive.git/hooks/pre-commit.sample
+t/lib/repositories/recursive/barerecursive.git/hooks/pre-rebase.sample
+t/lib/repositories/recursive/barerecursive.git/hooks/prepare-commit-msg.sample
+t/lib/repositories/recursive/barerecursive.git/hooks/update.sample
+t/lib/repositories/recursive/barerecursive.git/info/exclude
+t/lib/repositories/recursive/goingdeeper/scratch.git/config
+t/lib/repositories/recursive/goingdeeper/scratch.git/description
+t/lib/repositories/recursive/goingdeeper/scratch.git/HEAD
+t/lib/repositories/recursive/goingdeeper/scratch.git/hooks/applypatch-msg.sample
+t/lib/repositories/recursive/goingdeeper/scratch.git/hooks/commit-msg.sample
+t/lib/repositories/recursive/goingdeeper/scratch.git/hooks/post-commit.sample
+t/lib/repositories/recursive/goingdeeper/scratch.git/hooks/post-receive.sample
+t/lib/repositories/recursive/goingdeeper/scratch.git/hooks/post-update.sample
+t/lib/repositories/recursive/goingdeeper/scratch.git/hooks/pre-applypatch.sample
+t/lib/repositories/recursive/goingdeeper/scratch.git/hooks/pre-commit.sample
+t/lib/repositories/recursive/goingdeeper/scratch.git/hooks/pre-rebase.sample
+t/lib/repositories/recursive/goingdeeper/scratch.git/hooks/prepare-commit-msg.sample
+t/lib/repositories/recursive/goingdeeper/scratch.git/hooks/update.sample
+t/lib/repositories/recursive/goingdeeper/scratch.git/info/exclude
+t/lib/repositories/recursive/nothinginhere/emptyfile
 t/lib/repositories/repo1/config
 t/lib/repositories/repo1/description
 t/lib/repositories/repo1/HEAD
@@ -12,4 +12,4 @@ Makefile\.old$
 \.shipit$
 script/bootstrap.pl
 script/env
-
+local-lib5/
@@ -1,15 +1,17 @@
 ---
 abstract: 'A modern git web viewer'
 author:
+  - 'AND COPYRIGHT'
   - 'Dan Brook <broq@cpan.org>'
 build_requires:
   ExtUtils::MakeMaker: 6.42
+  Test::Exception: 0.31
   Test::More: 0.88
   Test::utf8: 0.02
 configure_requires:
   ExtUtils::MakeMaker: 6.42
 distribution_type: module
-generated_by: 'Module::Install version 0.91'
+generated_by: 'Module::Install version 1.00'
 license: gpl2
 meta-spec:
   url: http://module-build.sourceforge.net/META-spec-v1.4.html
@@ -22,7 +24,7 @@ no_index:
 provides:
   Gitalist:
     file: lib/Gitalist.pm
-    version: 0.002006
+    version: 0.002007
   Gitalist::ActionRole::FilenameArgs:
     file: lib/Gitalist/ActionRole/FilenameArgs.pm
   Gitalist::ContentMangler::Resolver:
@@ -53,10 +55,14 @@ provides:
     file: lib/Gitalist/Git/CollectionOfRepositories.pm
   Gitalist::Git::CollectionOfRepositories::FromDirectory:
     file: lib/Gitalist/Git/CollectionOfRepositories/FromDirectory.pm
+  Gitalist::Git::CollectionOfRepositories::FromDirectoryRecursive:
+    file: lib/Gitalist/Git/CollectionOfRepositories/FromDirectoryRecursive.pm
   Gitalist::Git::CollectionOfRepositories::FromListOfDirectories:
     file: lib/Gitalist/Git/CollectionOfRepositories/FromListOfDirectories.pm
   Gitalist::Git::HasUtils:
     file: lib/Gitalist/Git/HasUtils.pm
+  Gitalist::Git::Head:
+    file: lib/Gitalist/Git/Head.pm
   Gitalist::Git::Object:
     file: lib/Gitalist/Git/Object.pm
   Gitalist::Git::Object::Blob:
@@ -71,6 +77,8 @@ provides:
     file: lib/Gitalist/Git/Object/Tree.pm
   Gitalist::Git::Repository:
     file: lib/Gitalist/Git/Repository.pm
+  Gitalist::Git::Tag:
+    file: lib/Gitalist/Git/Tag.pm
   Gitalist::Git::Types:
     file: lib/Gitalist/Git/Types.pm
   Gitalist::Git::Util:
@@ -148,4 +156,4 @@ resources:
   bugtracker: http://rt.cpan.org/Public/Dist/Display.html?Name=Gitalist
   license: http://opensource.org/licenses/gpl-2.0.php
   repository: git://git.shadowcat.co.uk/catagits/Gitalist.git
-version: 0.002006
+version: 0.002007
@@ -106,8 +106,9 @@ requires 'Sys::Hostname';
 
 requires_external_bin 'git';
 
-test_requires 'Test::More' => '0.88';
-test_requires 'Test::utf8' => '0.02';
+test_requires 'Test::More'      => '0.88';
+test_requires 'Test::utf8'      => '0.02';
+test_requires 'Test::Exception' => '0.31';
 
 resources bugtracker => 'http://rt.cpan.org/Public/Dist/Display.html?Name=Gitalist';
 resources repository => 'git://git.shadowcat.co.uk/catagits/Gitalist.git';
@@ -6,7 +6,7 @@ SYNOPSIS
 
 INSTALL
     As Gitalist follows the usual Perl module format the usual approach for
-    installation should work e.g.
+    installation should work, e.g.:
 
       perl Makefile.PL
       make
@@ -17,20 +17,20 @@ INSTALL
 
       cpan -i Gitalist
 
-    You can also check gitalist out from git and run it, in this case you'll
-    additionally need the author modules, but no configuration will be
-    needed as it will default to looking for repositories the directory
-    above the checkout.
+    You can also check Gitalist out from its git repository and run it, in
+    this case you'll additionally need the author modules, but no
+    configuration will be needed as it will default to looking for
+    repositories the directory above the checkout.
 
 DESCRIPTION
-    Gitalist is a web frontend for git repositories based on gitweb.cgi and
-    backed by Catalyst.
+    Gitalist is a web frontend for git repositories based on <gitweb.cgi>
+    and backed by Catalyst.
 
   History
-    This project started off as an attempt to port gitweb.cgi to a Catalyst
-    app in a piecemeal fashion. As it turns out, thanks largely to Florian
-    Ragwitz's earlier effort, it was easier to use gitweb.cgi as a template
-    for building a new Catalyst application.
+    This project started off as an attempt to port *gitweb.cgi* to a
+    Catalyst app in a piecemeal fashion. As it turns out, thanks largely to
+    Florian Ragwitz's earlier effort, it was easier to use *gitweb.cgi* as a
+    template for building a new Catalyst application.
 
 GETTING GITALIST
     You can install Gitalist from CPAN in the usual way:
@@ -43,8 +43,9 @@ GETTING GITALIST
 
         git://git.shadowcat.co.uk/catagits/Gitalist.git
 
-    Gitalist is also mirrored to github, and a number of people have active
-    forks with branches and/or new features in the master branch.
+    Gitalist is also mirrored to GitHub at
+    <https://github.com/broquaint/Gitalist>, and a number of people have
+    active forks with branches and/or new features in the master branch.
 
 BOOTSTRAPPING
     As of 0.002001 Gitalist can now be bootstrapped to run out of its own
@@ -53,9 +54,9 @@ BOOTSTRAPPING
     path with CPAN they are installed under the Gitalist directory.
 
     To do this clone Gitalist from the Shadowcat repository mentioned above
-    or grab a snapshot from broquaint's github repository:
+    or grab a snapshot from broquaint's GitHub repository:
 
-        http://github.com/broquaint/Gitalist/downloads
+        https://github.com/broquaint/Gitalist/downloads
 
     With the source acquired and unpacked run the following from within the
     Gitalist directory:
@@ -65,7 +66,7 @@ BOOTSTRAPPING
     This will install the necessary modules for the build process which in
     turn installs the prerequisites locally.
 
-    *NB* The relevant bootstrap scripts aren't available in the CPAN dist as
+    NB: The relevant bootstrap scripts aren't available in the CPAN dist as
     the bootstrap scripts should not be installed.
 
 INITIAL CONFIGURATION
@@ -95,8 +96,8 @@ INITIAL CONFIGURATION
 
       cp `perl -Ilib -MGitalist -e'print Gitalist->path_to("gitalist.conf")'` gitalist.conf
 
-    You can then edit this confg, adding a repo_dir path and customising
-    other settings as desired.
+    You can then edit this configuration, adding a "repo_dir" path and
+    customising other settings as desired.
 
     You can then start the Gitalist demo server by setting
     "GITALIST_CONFIG". For example:
@@ -121,7 +122,7 @@ RUNNING
     than using the single threaded developement server.
 
     The recommended deployment method for Gitalist is FastCGI, although
-    Gitalist can also be run under mod_perl or as pure perl with
+    Gitalist can also be run under <mod_perl> or as pure Perl with
     Catalyst::Engine::PreFork.
 
     Assuming that you have installed Gitalist's dependencies into a
@@ -137,42 +138,48 @@ RUNNING
         http://example.gitalist.com
 
   FASTCGI
-        Running Gitalist in FastCGI mode requires a webserver with FastCGI
-        support (such as apache with mod_fcgi or fcgid). Below is a sample 
-        configuration using Apache2 with fcgid in a dynamic configuration
-        (as opposed to static or standalone mode). More information on these modes and 
-        their configuration can be found at 
-        http://search.cpan.org/~bobtfish/Catalyst-Runtime-5.80025/lib/Catalyst/Engine/FastCGI.pm#Standalone_server_mode
-            In Apache's mime.conf, add AddHandler fcgid-script .fcgi (or AddHandler fastcgi-script .fcgi for mod_fcgi)
-                        
-            And a quick VirtualHost configuration:
-                        
-            <VirtualHost *:80>
-              ServerName gitalist.yourdomain.com
-              DocumentRoot /path/to/gitalist.fcgi
-              <Directory "/path/to/gitalist.fcgi">
+    Running Gitalist in FastCGI mode requires a webserver with FastCGI
+    support (such as apache with <mod_fcgi> or <mod_fcgid>). Below is a
+    sample configuration using Apache2 with mod_fcgid in a dynamic
+    configuration (as opposed to static or standalone mode). More
+    information on these modes and their configuration can be found at
+    "Standalone server mode" in Catalyst::Engine::FastCGI.
+
+    In Apache's mime.conf, add "AddHandler fcgid-script .fcgi" (or
+    "AddHandler fastcgi-script .fcgi" for mod_fcgi).
+
+    And a quick VirtualHost configuration:
+
+        <VirtualHost *:80>
+            ServerName gitalist.yourdomain.com
+            DocumentRoot /path/to/gitalist.fcgi
+            <Directory "/path/to/gitalist.fcgi">
                 AllowOverride all
                 Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
                 Order allow,deny
                 Allow from all
-              </Directory>
+            </Directory>
 
             # Tell Apache this is a FastCGI application
             <Files gitalist.fcgi>
                 #change the below to fastcgi-script if using mod_fcgi
                 SetHandler fcgid-script
             </Files>
-          </VirtualHost>
-                        
-            Now to access your gitalist instance, you'll go to gitalist.yourdomain.com/gitalist.fcgi/ 
-            (DO NOT FORGET THAT TRAILING /). If you'd like a different URL, of course, you'll likely want to use 
-            mod_rewrite or equivalent
-                        
-            If you find the need to do some troubleshooting, you can call http://url_to_gitalist.fcgi?dump_info=1
-            and/or add export GITALIST_DEBUG=1 to the top of you gitalist.fcgi file (just below the shebang line).
-                
-            Also, note that  Apache will refuse %2F in Gitalist URL's unless configured otherwise. Make sure
-            "AllowEncodedSlashes On" is in your httpd.conf file in order for this to run smoothly.
+        </VirtualHost>
+
+    Now to access your Gitalist instance, you'll go to
+    "gitalist.yourdomain.com/gitalist.fcgi/" (do not forget that trailing
+    "/"). If you'd like a different URL, of course, you'll likely want to
+    use <mod_rewrite> or equivalent.
+
+    If you find the need to do some troubleshooting, you can call
+    "http://url_to_gitalist.fcgi?dump_info=1" and/or add export
+    "GITALIST_DEBUG=1" to the top of your gitalist.fcgi file (just below the
+    shebang line).
+
+    Also, note that Apache will refuse %2F in Gitalist URLs unless
+    configured otherwise. Make sure "AllowEncodedSlashes On" is in your
+    httpd.conf file in order for this to run smoothly.
 
 CONTRIBUTING
     Patches are welcome, please feel free to fork on github and send pull
@@ -194,16 +201,16 @@ SEE ALSO
 
 AUTHORS AND COPYRIGHT
       Catalyst application:
-        (C) 2009 Venda Ltd and Dan Brook <broq@cpan.org>
-        (C) 2009, Tom Doran <bobtfish@bobtfish.net>
-        (C) 2009, Zac Stevens <zts@cryptocracy.com>
+        © 2009 Venda Ltd and Dan Brook <broq@cpan.org>
+        © 2009, Tom Doran <bobtfish@bobtfish.net>
+        © 2009, Zac Stevens <zts@cryptocracy.com>
 
       Original gitweb.cgi from which this was derived:
-        (C) 2005-2006, Kay Sievers <kay.sievers@vrfy.org>
-        (C) 2005, Christian Gierke
+        © 2005-2006, Kay Sievers <kay.sievers@vrfy.org>
+        © 2005, Christian Gierke
 
       Model based on http://github.com/rafl/gitweb
-        (C) 2008, Florian Ragwitz
+        © 2008, Florian Ragwitz
 
 LICENSE
     Licensed under GNU GPL v2
@@ -253,6 +253,8 @@ sub import {
     # import to main::
     no strict 'refs';
     *{'main::WriteMakefile'} = \&Write if caller(0) eq 'main';
+
+    return (@Existing, @Missing);
 }
 
 sub _running_under {
@@ -672,7 +674,20 @@ sub _load {
 sub _load_cpan {
     return if $CPAN::VERSION and $CPAN::Config and not @_;
     require CPAN;
-    if ( $CPAN::HandleConfig::VERSION ) {
+
+    # CPAN-1.82+ adds CPAN::Config::AUTOLOAD to redirect to
+    #    CPAN::HandleConfig->load. CPAN reports that the redirection
+    #    is deprecated in a warning printed at the user.
+
+    # CPAN-1.81 expects CPAN::HandleConfig->load, does not have
+    #   $CPAN::HandleConfig::VERSION but cannot handle
+    #   CPAN::Config->load
+
+    # Which "versions expect CPAN::Config->load?
+
+    if ( $CPAN::HandleConfig::VERSION
+        || CPAN::HandleConfig->can('load')
+    ) {
         # Newer versions of CPAN have a HandleConfig module
         CPAN::HandleConfig->load;
     } else {
@@ -802,4 +817,4 @@ END_MAKE
 
 __END__
 
-#line 1056
+#line 1071
@@ -0,0 +1,38 @@
+#line 1
+use strict;
+use warnings;
+
+package Module::Install::AuthorRequires;
+
+use base 'Module::Install::Base';
+
+# cargo cult
+BEGIN {
+    our $VERSION = '0.02';
+    our $ISCORE  = 1;
+}
+
+sub author_requires {
+    my $self = shift;
+
+    return $self->{values}->{author_requires}
+        unless @_;
+
+    my @added;
+    while (@_) {
+        my $mod = shift or last;
+        my $version = shift || 0;
+        push @added, [$mod => $version];
+    }
+
+    push @{ $self->{values}->{author_requires} }, @added;
+    $self->admin->author_requires(@added);
+
+    return map { @$_ } @added;
+}
+
+1;
+
+__END__
+
+#line 92
@@ -0,0 +1,59 @@
+#line 1
+package Module::Install::AuthorTests;
+
+use 5.005;
+use strict;
+use Module::Install::Base;
+use Carp ();
+
+#line 16
+
+use vars qw{$VERSION $ISCORE @ISA};
+BEGIN {
+  $VERSION = '0.002';
+  $ISCORE  = 1;
+  @ISA     = qw{Module::Install::Base};
+}
+
+#line 42
+
+sub author_tests {
+  my ($self, @dirs) = @_;
+  _add_author_tests($self, \@dirs, 0);
+}
+
+#line 56
+
+sub recursive_author_tests {
+  my ($self, @dirs) = @_;
+  _add_author_tests($self, \@dirs, 1);
+}
+
+sub _wanted {
+  my $href = shift;
+  sub { /\.t$/ and -f $_ and $href->{$File::Find::dir} = 1 }
+}
+
+sub _add_author_tests {
+  my ($self, $dirs, $recurse) = @_;
+  return unless $Module::Install::AUTHOR;
+
+  my @tests = $self->tests ? (split / /, $self->tests) : 't/*.t';
+
+  # XXX: pick a default, later -- rjbs, 2008-02-24
+  my @dirs = @$dirs ? @$dirs : Carp::confess "no dirs given to author_tests";
+     @dirs = grep { -d } @dirs;
+
+  if ($recurse) {
+    require File::Find;
+    my %test_dir;
+    File::Find::find(_wanted(\%test_dir), @dirs);
+    $self->tests( join ' ', @tests, map { "$_/*.t" } sort keys %test_dir );
+  } else {
+    $self->tests( join ' ', @tests, map { "$_/*.t" } sort @dirs );
+  }
+}
+
+#line 107
+
+1;
@@ -6,7 +6,7 @@ use Module::Install::Base ();
 
 use vars qw{$VERSION @ISA $ISCORE};
 BEGIN {
-	$VERSION = '0.91';
+	$VERSION = '1.00';
 	@ISA     = 'Module::Install::Base';
 	$ISCORE  = 1;
 }
@@ -37,12 +37,33 @@ sub auto_install {
     $self->include('Module::AutoInstall');
     require Module::AutoInstall;
 
-    Module::AutoInstall->import(
+    my @features_require = Module::AutoInstall->import(
         (@config ? (-config => \@config) : ()),
         (@core   ? (-core   => \@core)   : ()),
         $self->features,
     );
 
+    my %seen;
+    my @requires = map @$_, map @$_, grep ref, $self->requires;
+    while (my ($mod, $ver) = splice(@requires, 0, 2)) {
+        $seen{$mod}{$ver}++;
+    }
+    my @build_requires = map @$_, map @$_, grep ref, $self->build_requires;
+    while (my ($mod, $ver) = splice(@build_requires, 0, 2)) {
+        $seen{$mod}{$ver}++;
+    }
+    my @configure_requires = map @$_, map @$_, grep ref, $self->configure_requires;
+    while (my ($mod, $ver) = splice(@configure_requires, 0, 2)) {
+        $seen{$mod}{$ver}++;
+    }
+
+    my @deduped;
+    while (my ($mod, $ver) = splice(@features_require, 0, 2)) {
+        push @deduped, $mod => $ver unless $seen{$mod}{$ver}++;
+    }
+
+    $self->requires(@deduped);
+
     $self->makemaker_args( Module::AutoInstall::_make_args() );
 
     my $class = ref($self);
@@ -4,7 +4,7 @@ package Module::Install::Base;
 use strict 'vars';
 use vars qw{$VERSION};
 BEGIN {
-	$VERSION = '0.91';
+	$VERSION = '1.00';
 }
 
 # Suspend handler for "redefined" warnings
@@ -51,13 +51,18 @@ sub admin {
 #line 106
 
 sub is_admin {
-	$_[0]->admin->VERSION;
+	! $_[0]->admin->isa('Module::Install::Base::FakeAdmin');
 }
 
 sub DESTROY {}
 
 package Module::Install::Base::FakeAdmin;
 
+use vars qw{$VERSION};
+BEGIN {
+	$VERSION = $Module::Install::Base::VERSION;
+}
+
 my $fake;
 
 sub new {
@@ -75,4 +80,4 @@ BEGIN {
 
 1;
 
-#line 154
+#line 159
@@ -9,7 +9,7 @@ use Module::Install::Base ();
 
 use vars qw{$VERSION @ISA $ISCORE};
 BEGIN {
-	$VERSION = '0.91';
+	$VERSION = '1.00';
 	@ISA     = 'Module::Install::Base';
 	$ISCORE  = 1;
 }
@@ -9,25 +9,35 @@ require Module::Install::Base;
 
 use File::Find;
 use FindBin;
-use File::Copy::Recursive 'rcopy';
+use File::Copy::Recursive;
 use File::Spec ();
+use Getopt::Long ();
+use Data::Dumper;
 
 my $SAFETY = 0;
 
 our @IGNORE =
   qw/Build Build.PL Changes MANIFEST META.yml Makefile.PL Makefile README
-  _build blib lib script t inc \.svn \.git _darcs \.bzr \.hg/;
+  _build blib lib script t inc .*\.svn \.git _darcs \.bzr \.hg
+  debian build-stamp install-stamp configure-stamp/;
 our @CLASSES   = ();
 our $ENGINE    = 'CGI';
-our $CORE      = 0;
-our $MULTIARCH = 0;
 our $SCRIPT    = '';
 our $USAGE     = '';
+our %PAROPTS   = ();
 
-#line 42
+#line 57
 
 sub catalyst {
     my $self = shift;
+
+    if($Module::Install::AUTHOR) {
+        $self->admin->copy_package(
+            'File::Copy::Recursive',
+            $INC{"File/Copy/Recursive.pm"},
+        );
+    }
+
     print <<EOF;
 *** Module::Install::Catalyst
 EOF
@@ -38,7 +48,7 @@ EOF
 EOF
 }
 
-#line 58
+#line 85
 
 sub catalyst_files {
     my $self = shift;
@@ -58,25 +68,25 @@ sub catalyst_files {
     my @path = split '-', $self->name;
     for my $orig (@files) {
         my $path = File::Spec->catdir( 'blib', 'lib', @path, $orig );
-        rcopy( $orig, $path );
+        File::Copy::Recursive::rcopy( $orig, $path );
     }
 }
 
-#line 84
+#line 113
 
 sub catalyst_ignore_all {
     my ( $self, $ignore ) = @_;
     @IGNORE = @$ignore;
 }
 
-#line 93
+#line 124
 
 sub catalyst_ignore {
     my ( $self, @ignore ) = @_;
     push @IGNORE, @ignore;
 }
 
-#line 102
+#line 133
 
 # Workaround for a namespace conflict
 sub catalyst_par {
@@ -89,51 +99,75 @@ sub catalyst_par {
     $usage =~ s/"/\\"/g;
     my $class_string = join "', '", @CLASSES;
     $class_string = "'$class_string'" if $class_string;
+    local $Data::Dumper::Indent = 0;
+    local $Data::Dumper::Terse = 1;
+    local $Data::Dumper::Pad = ' ';
+    my $paropts_string = Dumper(\%PAROPTS) || "{ }";
     $self->postamble(<<EOF);
 catalyst_par :: all
-\t\$(NOECHO) \$(PERL) -Ilib -Minc::Module::Install -MModule::Install::Catalyst -e"Catalyst::Module::Install::_catalyst_par( '$par', '$name', { CLASSES => [$class_string], CORE => $CORE, ENGINE => '$ENGINE', MULTIARCH => $MULTIARCH, SCRIPT => '$SCRIPT', USAGE => q#$usage# } )"
+\t\$(NOECHO) \$(PERL) -Ilib -Minc::Module::Install -MModule::Install::Catalyst -e"Catalyst::Module::Install::_catalyst_par( '$par', '$name', { CLASSES => [$class_string], PAROPTS => $paropts_string, ENGINE => '$ENGINE', SCRIPT => '$SCRIPT', USAGE => q#$usage# } )"
 EOF
     print <<EOF;
 Please run "make catalyst_par" to create the PAR package!
 EOF
 }
 
-#line 126
+#line 161
 
 sub catalyst_par_core {
     my ( $self, $core ) = @_;
-    $core ? ( $CORE = $core ) : $CORE++;
+    $core ? ( $PAROPTS{'B'} = $core ) : $PAROPTS{'B'}++;
 }
 
-#line 135
+#line 170
 
 sub catalyst_par_classes {
     my ( $self, @classes ) = @_;
     push @CLASSES, @classes;
 }
 
-#line 144
+#line 179
 
 sub catalyst_par_engine {
     my ( $self, $engine ) = @_;
     $ENGINE = $engine;
 }
 
-#line 153
+#line 188
 
 sub catalyst_par_multiarch {
     my ( $self, $multiarch ) = @_;
-    $multiarch ? ( $MULTIARCH = $multiarch ) : $MULTIARCH++;
+    $multiarch ? ( $PAROPTS{'m'} = $multiarch ) : $PAROPTS{'m'}++;
 }
 
-#line 162
+#line 221
+
+sub catalyst_par_options {
+    my ( $self, $optstring ) = @_;
+    eval "use PAR::Packer ()";
+    if ($@) {
+        warn "WARNING: catalyst_par_options ignored - you need PAR::Packer\n"
+    }
+    else {
+        my $p = Getopt::Long::Parser->new(config => ['no_ignore_case']);
+        my %o;
+        require Text::ParseWords;
+        {
+            local @ARGV = Text::ParseWords::shellwords($optstring);
+            $p->getoptions(\%o, PAR::Packer->options);
+        }
+        %PAROPTS = ( %PAROPTS, %o);
+    }
+}
+
+#line 243
 
 sub catalyst_par_script {
     my ( $self, $script ) = @_;
     $SCRIPT = $script;
 }
 
-#line 171
+#line 252
 
 sub catalyst_par_usage {
     my ( $self, $usage ) = @_;
@@ -154,8 +188,7 @@ sub _catalyst_par {
     my $CLASSES   = $opts->{CLASSES} || [];
     my $USAGE     = $opts->{USAGE};
     my $SCRIPT    = $opts->{SCRIPT};
-    my $MULTIARCH = $opts->{MULTIARCH};
-    my $CORE      = $opts->{CORE};
+    my $PAROPTS   = $opts->{PAROPTS};
 
     my $name = $class_name;
     $name =~ s/::/_/g;
@@ -261,14 +294,16 @@ EOF
     open my $olderr, '>&STDERR';
     open STDERR, '>', File::Spec->devnull;
     my %opt = (
+        %{$PAROPTS},
+        # take user defined options first and override them with harcoded defaults
         'x' => 1,
         'n' => 0,
         'o' => $par,
-        'a' => [ grep( !/par.pl/, glob '.' ) ],
         'p' => 1,
-        'B' => $CORE,
-        'm' => $MULTIARCH
     );
+    # do not replace the whole $opt{'a'} array; just push required default value
+    push @{$opt{'a'}}, grep( !/par.pl/, glob '.' );
+
     App::Packer::PAR->new(
         frontend  => 'Module::ScanDeps',
         backend   => 'PAR::Packer',
@@ -285,6 +320,6 @@ EOF
     return 1;
 }
 
-#line 332
+#line 414
 
 1;
@@ -8,7 +8,7 @@ use Module::Install::Base ();
 
 use vars qw{$VERSION $ISCORE @ISA};
 BEGIN {
-	$VERSION = '0.91';
+	$VERSION = '1.00';
 	$ISCORE  = 1;
 	@ISA     = qw{Module::Install::Base};
 }
@@ -6,7 +6,7 @@ use Module::Install::Base ();
 
 use vars qw{$VERSION @ISA $ISCORE};
 BEGIN {
-	$VERSION = '0.91';
+	$VERSION = '1.00';
 	@ISA     = 'Module::Install::Base';
 	$ISCORE  = 1;
 }
@@ -6,7 +6,7 @@ use Module::Install::Base ();
 
 use vars qw{$VERSION @ISA $ISCORE};
 BEGIN {
-	$VERSION = '0.91';
+	$VERSION = '1.00';
 	@ISA     = 'Module::Install::Base';
 	$ISCORE  = 1;
 }
@@ -4,10 +4,11 @@ package Module::Install::Makefile;
 use strict 'vars';
 use ExtUtils::MakeMaker   ();
 use Module::Install::Base ();
+use Fcntl qw/:flock :seek/;
 
 use vars qw{$VERSION @ISA $ISCORE};
 BEGIN {
-	$VERSION = '0.91';
+	$VERSION = '1.00';
 	@ISA     = 'Module::Install::Base';
 	$ISCORE  = 1;
 }
@@ -25,8 +26,8 @@ sub prompt {
 		die "Caught an potential prompt infinite loop ($c[1]|$c[2]|$_[0])";
 	}
 
-	# In automated testing, always use defaults
-	if ( $ENV{AUTOMATED_TESTING} and ! $ENV{PERL_MM_USE_DEFAULT} ) {
+	# In automated testing or non-interactive session, always use defaults
+	if ( ($ENV{AUTOMATED_TESTING} or -! -t STDIN) and ! $ENV{PERL_MM_USE_DEFAULT} ) {
 		local $ENV{PERL_MM_USE_DEFAULT} = 1;
 		goto &ExtUtils::MakeMaker::prompt;
 	} else {
@@ -34,21 +35,112 @@ sub prompt {
 	}
 }
 
+# Store a cleaned up version of the MakeMaker version,
+# since we need to behave differently in a variety of
+# ways based on the MM version.
+my $makemaker = eval $ExtUtils::MakeMaker::VERSION;
+
+# If we are passed a param, do a "newer than" comparison.
+# Otherwise, just return the MakeMaker version.
+sub makemaker {
+	( @_ < 2 or $makemaker >= eval($_[1]) ) ? $makemaker : 0
+}
+
+# Ripped from ExtUtils::MakeMaker 6.56, and slightly modified
+# as we only need to know here whether the attribute is an array
+# or a hash or something else (which may or may not be appendable).
+my %makemaker_argtype = (
+ C                  => 'ARRAY',
+ CONFIG             => 'ARRAY',
+# CONFIGURE          => 'CODE', # ignore
+ DIR                => 'ARRAY',
+ DL_FUNCS           => 'HASH',
+ DL_VARS            => 'ARRAY',
+ EXCLUDE_EXT        => 'ARRAY',
+ EXE_FILES          => 'ARRAY',
+ FUNCLIST           => 'ARRAY',
+ H                  => 'ARRAY',
+ IMPORTS            => 'HASH',
+ INCLUDE_EXT        => 'ARRAY',
+ LIBS               => 'ARRAY', # ignore ''
+ MAN1PODS           => 'HASH',
+ MAN3PODS           => 'HASH',
+ META_ADD           => 'HASH',
+ META_MERGE         => 'HASH',
+ PL_FILES           => 'HASH',
+ PM                 => 'HASH',
+ PMLIBDIRS          => 'ARRAY',
+ PMLIBPARENTDIRS    => 'ARRAY',
+ PREREQ_PM          => 'HASH',
+ CONFIGURE_REQUIRES => 'HASH',
+ SKIP               => 'ARRAY',
+ TYPEMAPS           => 'ARRAY',
+ XS                 => 'HASH',
+# VERSION            => ['version',''],  # ignore
+# _KEEP_AFTER_FLUSH  => '',
+
+ clean      => 'HASH',
+ depend     => 'HASH',
+ dist       => 'HASH',
+ dynamic_lib=> 'HASH',
+ linkext    => 'HASH',
+ macro      => 'HASH',
+ postamble  => 'HASH',
+ realclean  => 'HASH',
+ test       => 'HASH',
+ tool_autosplit => 'HASH',
+
+ # special cases where you can use makemaker_append
+ CCFLAGS   => 'APPENDABLE',
+ DEFINE    => 'APPENDABLE',
+ INC       => 'APPENDABLE',
+ LDDLFLAGS => 'APPENDABLE',
+ LDFROM    => 'APPENDABLE',
+);
+
 sub makemaker_args {
-	my $self = shift;
+	my ($self, %new_args) = @_;
 	my $args = ( $self->{makemaker_args} ||= {} );
-	%$args = ( %$args, @_ );
+	foreach my $key (keys %new_args) {
+		if ($makemaker_argtype{$key}) {
+			if ($makemaker_argtype{$key} eq 'ARRAY') {
+				$args->{$key} = [] unless defined $args->{$key};
+				unless (ref $args->{$key} eq 'ARRAY') {
+					$args->{$key} = [$args->{$key}]
+				}
+				push @{$args->{$key}},
+					ref $new_args{$key} eq 'ARRAY'
+						? @{$new_args{$key}}
+						: $new_args{$key};
+			}
+			elsif ($makemaker_argtype{$key} eq 'HASH') {
+				$args->{$key} = {} unless defined $args->{$key};
+				foreach my $skey (keys %{ $new_args{$key} }) {
+					$args->{$key}{$skey} = $new_args{$key}{$skey};
+				}
+			}
+			elsif ($makemaker_argtype{$key} eq 'APPENDABLE') {
+				$self->makemaker_append($key => $new_args{$key});
+			}
+		}
+		else {
+			if (defined $args->{$key}) {
+				warn qq{MakeMaker attribute "$key" is overriden; use "makemaker_append" to append values\n};
+			}
+			$args->{$key} = $new_args{$key};
+		}
+	}
 	return $args;
 }
 
 # For mm args that take multiple space-seperated args,
 # append an argument to the current list.
 sub makemaker_append {
-	my $self = sShift;
+	my $self = shift;
 	my $name = shift;
 	my $args = $self->makemaker_args;
-	$args->{name} = defined $args->{$name}
-		? join( ' ', $args->{name}, @_ )
+	$args->{$name} = defined $args->{$name}
+		? join( ' ', $args->{$name}, @_ )
 		: join( ' ', @_ );
 }
 
@@ -89,25 +181,22 @@ sub inc {
 	$self->makemaker_args( INC => shift );
 }
 
-my %test_dir = ();
-
 sub _wanted_t {
-	/\.t$/ and -f $_ and $test_dir{$File::Find::dir} = 1;
 }
 
 sub tests_recursive {
 	my $self = shift;
-	if ( $self->tests ) {
-		die "tests_recursive will not work if tests are already defined";
-	}
 	my $dir = shift || 't';
 	unless ( -d $dir ) {
 		die "tests_recursive dir '$dir' does not exist";
 	}
-	%test_dir = ();
+	my %tests = map { $_ => 1 } split / /, ($self->tests || '');
 	require File::Find;
-	File::Find::find( \&_wanted_t, $dir );
-	$self->tests( join ' ', map { "$_/*.t" } sort keys %test_dir );
+	File::Find::find(
+        sub { /\.t$/ and -f $_ and $tests{"$File::Find::dir/*.t"} = 1 },
+        $dir
+    );
+	$self->tests( join ' ', sort keys %tests );
 }
 
 sub write {
@@ -130,12 +219,13 @@ sub write {
 		# an underscore, even though its own version may contain one!
 		# Hence the funny regexp to get rid of it.  See RT #35800
 		# for details.
-		$self->build_requires( 'ExtUtils::MakeMaker' => $ExtUtils::MakeMaker::VERSION =~ /^(\d+\.\d+)/ );
-		$self->configure_requires( 'ExtUtils::MakeMaker' => $ExtUtils::MakeMaker::VERSION =~ /^(\d+\.\d+)/ );
+		my $v = $ExtUtils::MakeMaker::VERSION =~ /^(\d+\.\d+)/;
+		$self->build_requires(     'ExtUtils::MakeMaker' => $v );
+		$self->configure_requires( 'ExtUtils::MakeMaker' => $v );
 	} else {
 		# Allow legacy-compatibility with 5.005 by depending on the
 		# most recent EU:MM that supported 5.005.
-		$self->build_requires( 'ExtUtils::MakeMaker' => 6.42 );
+		$self->build_requires(     'ExtUtils::MakeMaker' => 6.42 );
 		$self->configure_requires( 'ExtUtils::MakeMaker' => 6.42 );
 	}
 
@@ -143,59 +233,115 @@ sub write {
 	my $args = $self->makemaker_args;
 	$args->{DISTNAME} = $self->name;
 	$args->{NAME}     = $self->module_name || $self->name;
-	$args->{VERSION}  = $self->version;
 	$args->{NAME}     =~ s/-/::/g;
+	$args->{VERSION}  = $self->version or die <<'EOT';
+ERROR: Can't determine distribution version. Please specify it
+explicitly via 'version' in Makefile.PL, or set a valid $VERSION
+in a module, and provide its file path via 'version_from' (or
+'all_from' if you prefer) in Makefile.PL.
+EOT
+
+	$DB::single = 1;
 	if ( $self->tests ) {
-		$args->{test} = { TESTS => $self->tests };
+		my @tests = split ' ', $self->tests;
+		my %seen;
+		$args->{test} = {
+			TESTS => (join ' ', grep {!$seen{$_}++} @tests),
+		};
+    } elsif ( $Module::Install::ExtraTests::use_extratests ) {
+        # Module::Install::ExtraTests doesn't set $self->tests and does its own tests via harness.
+        # So, just ignore our xt tests here.
+	} elsif ( -d 'xt' and ($Module::Install::AUTHOR or $ENV{RELEASE_TESTING}) ) {
+		$args->{test} = {
+			TESTS => join( ' ', map { "$_/*.t" } grep { -d $_ } qw{ t xt } ),
+		};
 	}
 	if ( $] >= 5.005 ) {
 		$args->{ABSTRACT} = $self->abstract;
-		$args->{AUTHOR}   = $self->author;
+		$args->{AUTHOR}   = join ', ', @{$self->author || []};
 	}
-	if ( eval($ExtUtils::MakeMaker::VERSION) >= 6.10 ) {
-		$args->{NO_META} = 1;
+	if ( $self->makemaker(6.10) ) {
+		$args->{NO_META}   = 1;
+		#$args->{NO_MYMETA} = 1;
 	}
-	if ( eval($ExtUtils::MakeMaker::VERSION) > 6.17 and $self->sign ) {
+	if ( $self->makemaker(6.17) and $self->sign ) {
 		$args->{SIGN} = 1;
 	}
 	unless ( $self->is_admin ) {
 		delete $args->{SIGN};
 	}
+	if ( $self->makemaker(6.31) and $self->license ) {
+		$args->{LICENSE} = $self->license;
+	}
 
-	# Merge both kinds of requires into prereq_pm
 	my $prereq = ($args->{PREREQ_PM} ||= {});
 	%$prereq = ( %$prereq,
-		map { @$_ }
+		map { @$_ } # flatten [module => version]
 		map { @$_ }
 		grep $_,
-		($self->configure_requires, $self->build_requires, $self->requires)
+		($self->requires)
 	);
 
 	# Remove any reference to perl, PREREQ_PM doesn't support it
 	delete $args->{PREREQ_PM}->{perl};
 
-	# merge both kinds of requires into prereq_pm
-	my $subdirs = ($args->{DIR} ||= []);
+	# Merge both kinds of requires into BUILD_REQUIRES
+	my $build_prereq = ($args->{BUILD_REQUIRES} ||= {});
+	%$build_prereq = ( %$build_prereq,
+		map { @$_ } # flatten [module => version]
+		map { @$_ }
+		grep $_,
+		($self->configure_requires, $self->build_requires)
+	);
+
+	# Remove any reference to perl, BUILD_REQUIRES doesn't support it
+	delete $args->{BUILD_REQUIRES}->{perl};
+
+	# Delete bundled dists from prereq_pm, add it to Makefile DIR
+	my $subdirs = ($args->{DIR} || []);
 	if ($self->bundles) {
+		my %processed;
 		foreach my $bundle (@{ $self->bundles }) {
-			my ($file, $dir) = @$bundle;
-			push @$subdirs, $dir if -d $dir;
-			delete $prereq->{$file};
+			my ($mod_name, $dist_dir) = @$bundle;
+			delete $prereq->{$mod_name};
+			$dist_dir = File::Basename::basename($dist_dir); # dir for building this module
+			if (not exists $processed{$dist_dir}) {
+				if (-d $dist_dir) {
+					# List as sub-directory to be processed by make
+					push @$subdirs, $dist_dir;
+				}
+				# Else do nothing: the module is already present on the system
+				$processed{$dist_dir} = undef;
+			}
 		}
 	}
 
+	unless ( $self->makemaker('6.55_03') ) {
+		%$prereq = (%$prereq,%$build_prereq);
+		delete $args->{BUILD_REQUIRES};
+	}
+
 	if ( my $perl_version = $self->perl_version ) {
 		eval "use $perl_version; 1"
 			or die "ERROR: perl: Version $] is installed, "
 			. "but we need version >= $perl_version";
+
+		if ( $self->makemaker(6.48) ) {
+			$args->{MIN_PERL_VERSION} = $perl_version;
+		}
 	}
 
-	$args->{INSTALLDIRS} = $self->installdirs;
+	if ($self->installdirs) {
+		warn qq{old INSTALLDIRS (probably set by makemaker_args) is overriden by installdirs\n} if $args->{INSTALLDIRS};
+		$args->{INSTALLDIRS} = $self->installdirs;
+	}
 
-	my %args = map { ( $_ => $args->{$_} ) } grep {defined($args->{$_})} keys %$args;
+	my %args = map {
+		( $_ => $args->{$_} ) } grep {defined($args->{$_} )
+	} keys %$args;
 
 	my $user_preop = delete $args{dist}->{PREOP};
-	if (my $preop = $self->admin->preop($user_preop)) {
+	if ( my $preop = $self->admin->preop($user_preop) ) {
 		foreach my $key ( keys %$preop ) {
 			$args{dist}->{$key} = $preop->{$key};
 		}
@@ -219,9 +365,9 @@ sub fix_up_makefile {
 		. ($self->postamble || '');
 
 	local *MAKEFILE;
-	open MAKEFILE, "< $makefile_name" or die "fix_up_makefile: Couldn't open $makefile_name: $!";
+	open MAKEFILE, "+< $makefile_name" or die "fix_up_makefile: Couldn't open $makefile_name: $!";
+	eval { flock MAKEFILE, LOCK_EX };
 	my $makefile = do { local $/; <MAKEFILE> };
-	close MAKEFILE or die $!;
 
 	$makefile =~ s/\b(test_harness\(\$\(TEST_VERBOSE\), )/$1'inc', /;
 	$makefile =~ s/( -I\$\(INST_ARCHLIB\))/ -Iinc$1/g;
@@ -241,7 +387,8 @@ sub fix_up_makefile {
 	# XXX - This is currently unused; not sure if it breaks other MM-users
 	# $makefile =~ s/^pm_to_blib\s+:\s+/pm_to_blib :: /mg;
 
-	open  MAKEFILE, "> $makefile_name" or die "fix_up_makefile: Couldn't open $makefile_name: $!";
+	seek MAKEFILE, 0, SEEK_SET;
+	truncate MAKEFILE, 0;
 	print MAKEFILE  "$preamble$makefile$postamble" or die $!;
 	close MAKEFILE  or die $!;
 
@@ -265,4 +412,4 @@ sub postamble {
 
 __END__
 
-#line 394
+#line 541
@@ -6,7 +6,7 @@ use Module::Install::Base ();
 
 use vars qw{$VERSION @ISA $ISCORE};
 BEGIN {
-	$VERSION = '0.91';
+	$VERSION = '1.00';
 	@ISA     = 'Module::Install::Base';
 	$ISCORE  = 1;
 }
@@ -19,7 +19,6 @@ my @scalar_keys = qw{
 	name
 	module_name
 	abstract
-	author
 	version
 	distribution_type
 	tests
@@ -43,8 +42,11 @@ my @resource_keys = qw{
 
 my @array_keys = qw{
 	keywords
+	author
 };
 
+*authors = \&author;
+
 sub Meta              { shift          }
 sub Meta_BooleanKeys  { @boolean_keys  }
 sub Meta_ScalarKeys   { @scalar_keys   }
@@ -176,43 +178,6 @@ sub perl_version {
 	$self->{values}->{perl_version} = $version;
 }
 
-#Stolen from M::B
-my %license_urls = (
-    perl         => 'http://dev.perl.org/licenses/',
-    apache       => 'http://apache.org/licenses/LICENSE-2.0',
-    artistic     => 'http://opensource.org/licenses/artistic-license.php',
-    artistic_2   => 'http://opensource.org/licenses/artistic-license-2.0.php',
-    lgpl         => 'http://opensource.org/licenses/lgpl-license.php',
-    lgpl2        => 'http://opensource.org/licenses/lgpl-2.1.php',
-    lgpl3        => 'http://opensource.org/licenses/lgpl-3.0.html',
-    bsd          => 'http://opensource.org/licenses/bsd-license.php',
-    gpl          => 'http://opensource.org/licenses/gpl-license.php',
-    gpl2         => 'http://opensource.org/licenses/gpl-2.0.php',
-    gpl3         => 'http://opensource.org/licenses/gpl-3.0.html',
-    mit          => 'http://opensource.org/licenses/mit-license.php',
-    mozilla      => 'http://opensource.org/licenses/mozilla1.1.php',
-    open_source  => undef,
-    unrestricted => undef,
-    restrictive  => undef,
-    unknown      => undef,
-);
-
-sub license {
-	my $self = shift;
-	return $self->{values}->{license} unless @_;
-	my $license = shift or die(
-		'Did not provide a value to license()'
-	);
-	$self->{values}->{license} = $license;
-
-	# Automatically fill in license URLs
-	if ( $license_urls{$license} ) {
-		$self->resources( license => $license_urls{$license} );
-	}
-
-	return 1;
-}
-
 sub all_from {
 	my ( $self, $file ) = @_;
 
@@ -230,6 +195,8 @@ sub all_from {
 		die("The path '$file' does not exist, or is not a file");
 	}
 
+	$self->{values}{all_from} = $file;
+
 	# Some methods pull from POD instead of code.
 	# If there is a matching .pod, use that instead
 	my $pod = $file;
@@ -240,7 +207,7 @@ sub all_from {
 	$self->name_from($file)         unless $self->name;
 	$self->version_from($file)      unless $self->version;
 	$self->perl_version_from($file) unless $self->perl_version;
-	$self->author_from($pod)        unless $self->author;
+	$self->author_from($pod)        unless @{$self->author || []};
 	$self->license_from($pod)       unless $self->license;
 	$self->abstract_from($pod)      unless $self->abstract;
 
@@ -350,6 +317,9 @@ sub version_from {
 	require ExtUtils::MM_Unix;
 	my ( $self, $file ) = @_;
 	$self->version( ExtUtils::MM_Unix->parse_version($file) );
+
+	# for version integrity check
+	$self->makemaker_args( VERSION_FROM => $file );
 }
 
 sub abstract_from {
@@ -360,7 +330,7 @@ sub abstract_from {
 			{ DISTNAME => $self->name },
 			'ExtUtils::MM_Unix'
 		)->parse_abstract($file)
-	 );
+	);
 }
 
 # Add both distribution and module name
@@ -385,11 +355,10 @@ sub name_from {
 	}
 }
 
-sub perl_version_from {
-	my $self = shift;
+sub _extract_perl_version {
 	if (
-		Module::Install::_read($_[0]) =~ m/
-		^
+		$_[0] =~ m/
+		^\s*
 		(?:use|require) \s*
 		v?
 		([\d_\.]+)
@@ -398,6 +367,16 @@ sub perl_version_from {
 	) {
 		my $perl_version = $1;
 		$perl_version =~ s{_}{}g;
+		return $perl_version;
+	} else {
+		return;
+	}
+}
+
+sub perl_version_from {
+	my $self = shift;
+	my $perl_version=_extract_perl_version(Module::Install::_read($_[0]));
+	if ($perl_version) {
 		$self->perl_version($perl_version);
 	} else {
 		warn "Cannot determine perl version info from $_[0]\n";
@@ -417,59 +396,164 @@ sub author_from {
 		([^\n]*)
 	/ixms) {
 		my $author = $1 || $2;
-		$author =~ s{E<lt>}{<}g;
-		$author =~ s{E<gt>}{>}g;
+
+		# XXX: ugly but should work anyway...
+		if (eval "require Pod::Escapes; 1") {
+			# Pod::Escapes has a mapping table.
+			# It's in core of perl >= 5.9.3, and should be installed
+			# as one of the Pod::Simple's prereqs, which is a prereq
+			# of Pod::Text 3.x (see also below).
+			$author =~ s{ E<( (\d+) | ([A-Za-z]+) )> }
+			{
+				defined $2
+				? chr($2)
+				: defined $Pod::Escapes::Name2character_number{$1}
+				? chr($Pod::Escapes::Name2character_number{$1})
+				: do {
+					warn "Unknown escape: E<$1>";
+					"E<$1>";
+				};
+			}gex;
+		}
+		elsif (eval "require Pod::Text; 1" && $Pod::Text::VERSION < 3) {
+			# Pod::Text < 3.0 has yet another mapping table,
+			# though the table name of 2.x and 1.x are different.
+			# (1.x is in core of Perl < 5.6, 2.x is in core of
+			# Perl < 5.9.3)
+			my $mapping = ($Pod::Text::VERSION < 2)
+				? \%Pod::Text::HTML_Escapes
+				: \%Pod::Text::ESCAPES;
+			$author =~ s{ E<( (\d+) | ([A-Za-z]+) )> }
+			{
+				defined $2
+				? chr($2)
+				: defined $mapping->{$1}
+				? $mapping->{$1}
+				: do {
+					warn "Unknown escape: E<$1>";
+					"E<$1>";
+				};
+			}gex;
+		}
+		else {
+			$author =~ s{E<lt>}{<}g;
+			$author =~ s{E<gt>}{>}g;
+		}
 		$self->author($author);
 	} else {
 		warn "Cannot determine author info from $_[0]\n";
 	}
 }
 
-sub license_from {
+#Stolen from M::B
+my %license_urls = (
+    perl         => 'http://dev.perl.org/licenses/',
+    apache       => 'http://apache.org/licenses/LICENSE-2.0',
+    apache_1_1   => 'http://apache.org/licenses/LICENSE-1.1',
+    artistic     => 'http://opensource.org/licenses/artistic-license.php',
+    artistic_2   => 'http://opensource.org/licenses/artistic-license-2.0.php',
+    lgpl         => 'http://opensource.org/licenses/lgpl-license.php',
+    lgpl2        => 'http://opensource.org/licenses/lgpl-2.1.php',
+    lgpl3        => 'http://opensource.org/licenses/lgpl-3.0.html',
+    bsd          => 'http://opensource.org/licenses/bsd-license.php',
+    gpl          => 'http://opensource.org/licenses/gpl-license.php',
+    gpl2         => 'http://opensource.org/licenses/gpl-2.0.php',
+    gpl3         => 'http://opensource.org/licenses/gpl-3.0.html',
+    mit          => 'http://opensource.org/licenses/mit-license.php',
+    mozilla      => 'http://opensource.org/licenses/mozilla1.1.php',
+    open_source  => undef,
+    unrestricted => undef,
+    restrictive  => undef,
+    unknown      => undef,
+);
+
+sub license {
 	my $self = shift;
-	if (
-		Module::Install::_read($_[0]) =~ m/
-		(
-			=head \d \s+
-			(?:licen[cs]e|licensing|copyright|legal)\b
-			.*?
-		)
-		(=head\\d.*|=cut.*|)
-		\z
-	/ixms ) {
-		my $license_text = $1;
-		my @phrases      = (
-			'under the same (?:terms|license) as (?:perl|the perl programming language) itself' => 'perl', 1,
-			'GNU general public license'         => 'gpl',         1,
-			'GNU public license'                 => 'gpl',         1,
-			'GNU lesser general public license'  => 'lgpl',        1,
-			'GNU lesser public license'          => 'lgpl',        1,
-			'GNU library general public license' => 'lgpl',        1,
-			'GNU library public license'         => 'lgpl',        1,
-			'BSD license'                        => 'bsd',         1,
-			'Artistic license'                   => 'artistic',    1,
-			'GPL'                                => 'gpl',         1,
-			'LGPL'                               => 'lgpl',        1,
-			'BSD'                                => 'bsd',         1,
-			'Artistic'                           => 'artistic',    1,
-			'MIT'                                => 'mit',         1,
-			'proprietary'                        => 'proprietary', 0,
-		);
-		while ( my ($pattern, $license, $osi) = splice(@phrases, 0, 3) ) {
-			$pattern =~ s{\s+}{\\s+}g;
-			if ( $license_text =~ /\b$pattern\b/i ) {
-				$self->license($license);
-				return 1;
-			}
+	return $self->{values}->{license} unless @_;
+	my $license = shift or die(
+		'Did not provide a value to license()'
+	);
+	$license = __extract_license($license) || lc $license;
+	$self->{values}->{license} = $license;
+
+	# Automatically fill in license URLs
+	if ( $license_urls{$license} ) {
+		$self->resources( license => $license_urls{$license} );
+	}
+
+	return 1;
+}
+
+sub _extract_license {
+	my $pod = shift;
+	my $matched;
+	return __extract_license(
+		($matched) = $pod =~ m/
+			(=head \d \s+ L(?i:ICEN[CS]E|ICENSING)\b.*?)
+			(=head \d.*|=cut.*|)\z
+		/xms
+	) || __extract_license(
+		($matched) = $pod =~ m/
+			(=head \d \s+ (?:C(?i:OPYRIGHTS?)|L(?i:EGAL))\b.*?)
+			(=head \d.*|=cut.*|)\z
+		/xms
+	);
+}
+
+sub __extract_license {
+	my $license_text = shift or return;
+	my @phrases      = (
+		'(?:under )?the same (?:terms|license) as (?:perl|the perl (?:\d )?programming language)' => 'perl', 1,
+		'(?:under )?the terms of (?:perl|the perl programming language) itself' => 'perl', 1,
+		'Artistic and GPL'                   => 'perl',         1,
+		'GNU general public license'         => 'gpl',          1,
+		'GNU public license'                 => 'gpl',          1,
+		'GNU lesser general public license'  => 'lgpl',         1,
+		'GNU lesser public license'          => 'lgpl',         1,
+		'GNU library general public license' => 'lgpl',         1,
+		'GNU library public license'         => 'lgpl',         1,
+		'GNU Free Documentation license'     => 'unrestricted', 1,
+		'GNU Affero General Public License'  => 'open_source',  1,
+		'(?:Free)?BSD license'               => 'bsd',          1,
+		'Artistic license'                   => 'artistic',     1,
+		'Apache (?:Software )?license'       => 'apache',       1,
+		'GPL'                                => 'gpl',          1,
+		'LGPL'                               => 'lgpl',         1,
+		'BSD'                                => 'bsd',          1,
+		'Artistic'                           => 'artistic',     1,
+		'MIT'                                => 'mit',          1,
+		'Mozilla Public License'             => 'mozilla',      1,
+		'Q Public License'                   => 'open_source',  1,
+		'OpenSSL License'                    => 'unrestricted', 1,
+		'SSLeay License'                     => 'unrestricted', 1,
+		'zlib License'                       => 'open_source',  1,
+		'proprietary'                        => 'proprietary',  0,
+	);
+	while ( my ($pattern, $license, $osi) = splice(@phrases, 0, 3) ) {
+		$pattern =~ s#\s+#\\s+#gs;
+		if ( $license_text =~ /\b$pattern\b/i ) {
+			return $license;
 		}
 	}
+	return '';
+}
 
-	warn "Cannot determine license info from $_[0]\n";
-	return 'unknown';
+sub license_from {
+	my $self = shift;
+	if (my $license=_extract_license(Module::Install::_read($_[0]))) {
+		$self->license($license);
+	} else {
+		warn "Cannot determine license info from $_[0]\n";
+		return 'unknown';
+	}
 }
 
 sub _extract_bugtracker {
-	my @links   = $_[0] =~ m#L<(\Qhttp://rt.cpan.org/\E[^>]+)>#g;
+	my @links   = $_[0] =~ m#L<(
+	 \Qhttp://rt.cpan.org/\E[^>]+|
+	 \Qhttp://github.com/\E[\w_]+/[\w_]+/issues|
+	 \Qhttp://code.google.com/p/\E[\w_\-]+/issues/list
+	 )>#gx;
 	my %links;
 	@links{@links}=();
 	@links=keys %links;
@@ -485,7 +569,7 @@ sub bugtracker_from {
 		return 0;
 	}
 	if ( @links > 1 ) {
-		warn "Found more than on rt.cpan.org link in $_[0]\n";
+		warn "Found more than one bugtracker link in $_[0]\n";
 		return 0;
 	}
 
@@ -532,8 +616,15 @@ sub _perl_version {
 	return $v;
 }
 
-
-
+sub add_metadata {
+    my $self = shift;
+    my %hash = @_;
+    for my $key (keys %hash) {
+        warn "add_metadata: $key is not prefixed with 'x_'.\n" .
+             "Use appopriate function to add non-private metadata.\n" unless $key =~ /^x_/;
+        $self->{values}->{$key} = $hash{$key};
+    }
+}
 
 
 ######################################################################
@@ -6,7 +6,7 @@ use Module::Install::Base ();
 
 use vars qw{$VERSION @ISA $ISCORE};
 BEGIN {
-	$VERSION = '0.91';
+	$VERSION = '1.00';
 	@ISA     = 'Module::Install::Base';
 	$ISCORE  = 1;
 }
@@ -6,7 +6,7 @@ use Module::Install::Base ();
 
 use vars qw{$VERSION @ISA $ISCORE};
 BEGIN {
-	$VERSION = '0.91';
+	$VERSION = '1.00';
 	@ISA     = 'Module::Install::Base';
 	$ISCORE  = 1;
 }
@@ -6,7 +6,7 @@ use Module::Install::Base ();
 
 use vars qw{$VERSION @ISA $ISCORE};
 BEGIN {
-	$VERSION = '0.91';;
+	$VERSION = '1.00';
 	@ISA     = qw{Module::Install::Base};
 	$ISCORE  = 1;
 }
@@ -26,7 +26,10 @@ sub WriteAll {
 
 	$self->check_nmake if $args{check_nmake};
 	unless ( $self->makemaker_args->{PL_FILES} ) {
-		$self->makemaker_args( PL_FILES => {} );
+		# XXX: This still may be a bit over-defensive...
+		unless ($self->makemaker(6.25)) {
+			$self->makemaker_args( PL_FILES => {} ) if -f 'Build.PL';
+		}
 	}
 
 	# Until ExtUtils::MakeMaker support MYMETA.yml, make sure
@@ -19,6 +19,9 @@ package Module::Install;
 
 use 5.005;
 use strict 'vars';
+use Cwd        ();
+use File::Find ();
+use File::Path ();
 
 use vars qw{$VERSION $MAIN};
 BEGIN {
@@ -28,7 +31,7 @@ BEGIN {
 	# This is not enforced yet, but will be some time in the next few
 	# releases once we can make sure it won't clash with custom
 	# Module::Install extensions.
-	$VERSION = '0.91';
+	$VERSION = '1.00';
 
 	# Storage for the pseudo-singleton
 	$MAIN    = undef;
@@ -38,18 +41,25 @@ BEGIN {
 
 }
 
+sub import {
+	my $class = shift;
+	my $self  = $class->new(@_);
+	my $who   = $self->_caller;
 
-
-
-
-# Whether or not inc::Module::Install is actually loaded, the
-# $INC{inc/Module/Install.pm} is what will still get set as long as
-# the caller loaded module this in the documented manner.
-# If not set, the caller may NOT have loaded the bundled version, and thus
-# they may not have a MI version that works with the Makefile.PL. This would
-# result in false errors or unexpected behaviour. And we don't want that.
-my $file = join( '/', 'inc', split /::/, __PACKAGE__ ) . '.pm';
-unless ( $INC{$file} ) { die <<"END_DIE" }
+	#-------------------------------------------------------------
+	# all of the following checks should be included in import(),
+	# to allow "eval 'require Module::Install; 1' to test
+	# installation of Module::Install. (RT #51267)
+	#-------------------------------------------------------------
+
+	# Whether or not inc::Module::Install is actually loaded, the
+	# $INC{inc/Module/Install.pm} is what will still get set as long as
+	# the caller loaded module this in the documented manner.
+	# If not set, the caller may NOT have loaded the bundled version, and thus
+	# they may not have a MI version that works with the Makefile.PL. This would
+	# result in false errors or unexpected behaviour. And we don't want that.
+	my $file = join( '/', 'inc', split /::/, __PACKAGE__ ) . '.pm';
+	unless ( $INC{$file} ) { die <<"END_DIE" }
 
 Please invoke ${\__PACKAGE__} with:
 
@@ -61,26 +71,28 @@ not:
 
 END_DIE
 
-
-
-
-
-# If the script that is loading Module::Install is from the future,
-# then make will detect this and cause it to re-run over and over
-# again. This is bad. Rather than taking action to touch it (which
-# is unreliable on some platforms and requires write permissions)
-# for now we should catch this and refuse to run.
-if ( -f $0 ) {
-	my $s = (stat($0))[9];
-
-	# If the modification time is only slightly in the future,
-	# sleep briefly to remove the problem.
-	my $a = $s - time;
-	if ( $a > 0 and $a < 5 ) { sleep 5 }
-
-	# Too far in the future, throw an error.
-	my $t = time;
-	if ( $s > $t ) { die <<"END_DIE" }
+	# This reportedly fixes a rare Win32 UTC file time issue, but
+	# as this is a non-cross-platform XS module not in the core,
+	# we shouldn't really depend on it. See RT #24194 for detail.
+	# (Also, this module only supports Perl 5.6 and above).
+	eval "use Win32::UTCFileTime" if $^O eq 'MSWin32' && $] >= 5.006;
+
+	# If the script that is loading Module::Install is from the future,
+	# then make will detect this and cause it to re-run over and over
+	# again. This is bad. Rather than taking action to touch it (which
+	# is unreliable on some platforms and requires write permissions)
+	# for now we should catch this and refuse to run.
+	if ( -f $0 ) {
+		my $s = (stat($0))[9];
+
+		# If the modification time is only slightly in the future,
+		# sleep briefly to remove the problem.
+		my $a = $s - time;
+		if ( $a > 0 and $a < 5 ) { sleep 5 }
+
+		# Too far in the future, throw an error.
+		my $t = time;
+		if ( $s > $t ) { die <<"END_DIE" }
 
 Your installer $0 has a modification time in the future ($s > $t).
 
@@ -89,15 +101,12 @@ This is known to create infinite loops in make.
 Please correct this, then run $0 again.
 
 END_DIE
-}
-
-
-
+	}
 
 
-# Build.PL was formerly supported, but no longer is due to excessive
-# difficulty in implementing every single feature twice.
-if ( $0 =~ /Build.PL$/i ) { die <<"END_DIE" }
+	# Build.PL was formerly supported, but no longer is due to excessive
+	# difficulty in implementing every single feature twice.
+	if ( $0 =~ /Build.PL$/i ) { die <<"END_DIE" }
 
 Module::Install no longer supports Build.PL.
 
@@ -107,23 +116,42 @@ Please remove all Build.PL files and only use the Makefile.PL installer.
 
 END_DIE
 
+	#-------------------------------------------------------------
 
+	# To save some more typing in Module::Install installers, every...
+	# use inc::Module::Install
+	# ...also acts as an implicit use strict.
+	$^H |= strict::bits(qw(refs subs vars));
 
+	#-------------------------------------------------------------
 
+	unless ( -f $self->{file} ) {
+		foreach my $key (keys %INC) {
+			delete $INC{$key} if $key =~ /Module\/Install/;
+		}
 
-# To save some more typing in Module::Install installers, every...
-# use inc::Module::Install
-# ...also acts as an implicit use strict.
-$^H |= strict::bits(qw(refs subs vars));
-
+		local $^W;
+		require "$self->{path}/$self->{dispatch}.pm";
+		File::Path::mkpath("$self->{prefix}/$self->{author}");
+		$self->{admin} = "$self->{name}::$self->{dispatch}"->new( _top => $self );
+		$self->{admin}->init;
+		@_ = ($class, _self => $self);
+		goto &{"$self->{name}::import"};
+	}
 
+	local $^W;
+	*{"${who}::AUTOLOAD"} = $self->autoload;
+	$self->preload;
 
+	# Unregister loader and worker packages so subdirs can use them again
+	delete $INC{'inc/Module/Install.pm'};
+	delete $INC{'Module/Install.pm'};
 
+	# Save to the singleton
+	$MAIN = $self;
 
-use Cwd        ();
-use File::Find ();
-use File::Path ();
-use FindBin;
+	return 1;
+}
 
 sub autoload {
 	my $self = shift;
@@ -136,7 +164,21 @@ sub autoload {
 			# Delegate back to parent dirs
 			goto &$code unless $cwd eq $pwd;
 		}
-		$$sym =~ /([^:]+)$/ or die "Cannot autoload $who - $sym";
+		unless ($$sym =~ s/([^:]+)$//) {
+			# XXX: it looks like we can't retrieve the missing function
+			# via $$sym (usually $main::AUTOLOAD) in this case.
+			# I'm still wondering if we should slurp Makefile.PL to
+			# get some context or not ...
+			my ($package, $file, $line) = caller;
+			die <<"EOT";
+Unknown function is found at $file line $line.
+Execution of $file aborted due to runtime errors.
+
+If you're a contributor to a project, you may need to install
+some Module::Install extensions from CPAN (or other repository).
+If you're a user of a module, please contact the author.
+EOT
+		}
 		my $method = $1;
 		if ( uc($method) eq $method ) {
 			# Do nothing
@@ -152,33 +194,6 @@ sub autoload {
 	};
 }
 
-sub import {
-	my $class = shift;
-	my $self  = $class->new(@_);
-	my $who   = $self->_caller;
-
-	unless ( -f $self->{file} ) {
-		require "$self->{path}/$self->{dispatch}.pm";
-		File::Path::mkpath("$self->{prefix}/$self->{author}");
-		$self->{admin} = "$self->{name}::$self->{dispatch}"->new( _top => $self );
-		$self->{admin}->init;
-		@_ = ($class, _self => $self);
-		goto &{"$self->{name}::import"};
-	}
-
-	*{"${who}::AUTOLOAD"} = $self->autoload;
-	$self->preload;
-
-	# Unregister loader and worker packages so subdirs can use them again
-	delete $INC{"$self->{file}"};
-	delete $INC{"$self->{path}.pm"};
-
-	# Save to the singleton
-	$MAIN = $self;
-
-	return 1;
-}
-
 sub preload {
 	my $self = shift;
 	unless ( $self->{extensions} ) {
@@ -204,6 +219,7 @@ sub preload {
 
 	my $who = $self->_caller;
 	foreach my $name ( sort keys %seen ) {
+		local $^W;
 		*{"${who}::$name"} = sub {
 			${"${who}::AUTOLOAD"} = "${who}::$name";
 			goto &{"${who}::AUTOLOAD"};
@@ -214,12 +230,18 @@ sub preload {
 sub new {
 	my ($class, %args) = @_;
 
+	delete $INC{'FindBin.pm'};
+	{
+		# to suppress the redefine warning
+		local $SIG{__WARN__} = sub {};
+		require FindBin;
+	}
+
 	# ignore the prefix on extension modules built from top level.
 	my $base_path = Cwd::abs_path($FindBin::Bin);
 	unless ( Cwd::abs_path(Cwd::cwd()) eq $base_path ) {
 		delete $args{prefix};
 	}
-
 	return $args{_self} if $args{_self};
 
 	$args{dispatch} ||= 'Admin';
@@ -272,8 +294,10 @@ END_DIE
 sub load_extensions {
 	my ($self, $path, $top) = @_;
 
+	my $should_reload = 0;
 	unless ( grep { ! ref $_ and lc $_ eq lc $self->{prefix} } @INC ) {
 		unshift @INC, $self->{prefix};
+		$should_reload = 1;
 	}
 
 	foreach my $rv ( $self->find_extensions($path) ) {
@@ -281,12 +305,13 @@ sub load_extensions {
 		next if $self->{pathnames}{$pkg};
 
 		local $@;
-		my $new = eval { require $file; $pkg->can('new') };
+		my $new = eval { local $^W; require $file; $pkg->can('new') };
 		unless ( $new ) {
 			warn $@ if $@;
 			next;
 		}
-		$self->{pathnames}{$pkg} = delete $INC{$file};
+		$self->{pathnames}{$pkg} =
+			$should_reload ? delete $INC{$file} : $INC{$file};
 		push @{$self->{extensions}}, &{$new}($pkg, _top => $top );
 	}
 
@@ -348,17 +373,24 @@ sub _caller {
 	return $call;
 }
 
+# Done in evals to avoid confusing Perl::MinimumVersion
+eval( $] >= 5.006 ? <<'END_NEW' : <<'END_OLD' ); die $@ if $@;
 sub _read {
 	local *FH;
-	if ( $] >= 5.006 ) {
-		open( FH, '<', $_[0] ) or die "open($_[0]): $!";
-	} else {
-		open( FH, "< $_[0]"  ) or die "open($_[0]): $!";
-	}
+	open( FH, '<', $_[0] ) or die "open($_[0]): $!";
+	my $string = do { local $/; <FH> };
+	close FH or die "close($_[0]): $!";
+	return $string;
+}
+END_NEW
+sub _read {
+	local *FH;
+	open( FH, "< $_[0]"  ) or die "open($_[0]): $!";
 	my $string = do { local $/; <FH> };
 	close FH or die "close($_[0]): $!";
 	return $string;
 }
+END_OLD
 
 sub _readperl {
 	my $string = Module::Install::_read($_[0]);
@@ -379,18 +411,26 @@ sub _readpod {
 	return $string;
 }
 
+# Done in evals to avoid confusing Perl::MinimumVersion
+eval( $] >= 5.006 ? <<'END_NEW' : <<'END_OLD' ); die $@ if $@;
 sub _write {
 	local *FH;
-	if ( $] >= 5.006 ) {
-		open( FH, '>', $_[0] ) or die "open($_[0]): $!";
-	} else {
-		open( FH, "> $_[0]"  ) or die "open($_[0]): $!";
+	open( FH, '>', $_[0] ) or die "open($_[0]): $!";
+	foreach ( 1 .. $#_ ) {
+		print FH $_[$_] or die "print($_[0]): $!";
 	}
+	close FH or die "close($_[0]): $!";
+}
+END_NEW
+sub _write {
+	local *FH;
+	open( FH, "> $_[0]"  ) or die "open($_[0]): $!";
 	foreach ( 1 .. $#_ ) {
 		print FH $_[$_] or die "print($_[0]): $!";
 	}
 	close FH or die "close($_[0]): $!";
 }
+END_OLD
 
 # _version is for processing module versions (eg, 1.03_05) not
 # Perl versions (eg, 5.8.1).
@@ -427,4 +467,4 @@ sub _CLASS ($) {
 
 1;
 
-# Copyright 2008 - 2009 Adam Kennedy.
+# Copyright 2008 - 2010 Adam Kennedy.
@@ -48,13 +48,13 @@ after tree => sub {
     my ( $self, $c ) = @_;
     my $repository = $c->stash->{Repository};
     my $commit  = $c->stash->{Commit};
-    my $tree    = $c->stash->{filename}
-      ? $repository->get_object($repository->hash_by_path($commit->sha1, $c->stash->{filename}))
-      : $repository->get_object($commit->tree_sha1)
+    my $tree_obj    = $c->stash->{filename}
+      ? $commit->sha_by_path($c->stash->{filename})
+      : $commit->tree->[0]
     ;
     $c->stash(
-        tree      => $tree,
-        tree_list => [$repository->list_tree($tree->sha1)],
+        tree      => $tree_obj,
+        tree_list => $tree_obj->tree,
     );
 };
 
@@ -98,12 +98,8 @@ after history => sub {
        ($filename ? (file => $filename) : ())
     );
 
-    my $file = $repository->get_object(
-        $repository->hash_by_path(
-            $repository->head_hash,
-            $filename
-        )
-    );
+    my $commit = $repository->get_object('HEAD');
+    my $file = $commit->sha_by_path($filename);
 
     my $page = $c->req->param('pg') || 0;
     $logargs{skip} = $c->req->param('pg') * $logargs{count}
@@ -0,0 +1,79 @@
+use MooseX::Declare;
+
+class Gitalist::Git::CollectionOfRepositories::FromDirectoryRecursive
+    with Gitalist::Git::CollectionOfRepositories {
+
+    use MooseX::Types::Common::String qw/NonEmptySimpleStr/;
+    use MooseX::Types::Path::Class qw/Dir/;
+
+    use Moose::Autobox;
+    use List::Util 'first';
+
+    has repo_dir => (
+        isa => Dir,
+        is => 'ro',
+        required => 1,
+        coerce => 1,
+    );
+
+    method BUILD {
+      # Make sure repo_dir is an absolute path so that ->contains() works correctly.
+      $self->repo_dir->resolve;
+    }
+
+    method _find_repos(Dir $dir) {
+      return map {
+        $self->_is_git_repo($_) ? $_ : $self->_find_repos($_)
+      } grep $_->is_dir, $dir->children;
+    }
+
+    method _get_path_for_repository_name (NonEmptySimpleStr $name) {
+      my $repo = first { $_->name eq $name } $self->repositories->flatten
+        or return;
+      return $repo->path;
+    }
+
+    ## Builders
+    method _build_repositories {
+      return [
+        map Gitalist::Git::Repository->new($_), $self->_find_repos( $self->repo_dir )
+      ];
+    }
+}                         # end class
+
+__END__
+
+=head1 NAME
+
+Gitalist::Git::CollectionOfRepositories::FromDirectoryRecursive - Model of recursive directories containing git repositories
+
+=head1 SYNOPSIS
+
+    my $repo = Gitalist::Git::CollectionOfRepositories::FromDirectoryRecursive->new( repo_dir => $Dir );
+    my $repository_list = $repo->repositories;
+    my $first_repository = $repository_list->[0];
+    my $named_repository = $repo->get_repository('Gitalist');
+
+=head1 DESCRIPTION
+
+This class provides a list of Repositories recursively found in the given directory.
+
+=head1 ATTRIBUTES
+
+=head2 repo_dir (C<Path::Class::Dir>)
+
+The filesystem root of the C<Repo>.
+
+=head1 SEE ALSO
+
+L<Gitalist::Git::CollectionOfRepositories>, L<Gitalist::Git::Repository>
+
+=head1 AUTHORS
+
+See L<Gitalist> for authors.
+
+=head1 LICENSE
+
+See L<Gitalist> for the license.
+
+=cut
@@ -14,11 +14,12 @@ role Gitalist::Git::CollectionOfRepositories {
     );
     method get_repository (NonEmptySimpleStr $name) {
         my $path = $self->_get_path_for_repository_name($name);
-        die "Not a valid git repository."
+        die "Couldn't get_repository '$name' - not a valid git repository."
             unless $self->_is_git_repo($path);
         return Repository->new( $path );
     }
     # Determine whether a given directory is a git repo.
+    # http://www.kernel.org/pub/software/scm/git/docs/gitrepository-layout.html
     method _is_git_repo ($dir) {
         return -f $dir->file('HEAD') || -f $dir->file('.git', 'HEAD');
     }
@@ -0,0 +1,57 @@
+package Gitalist::Git::Head;
+use Moose;
+use namespace::autoclean;
+
+use Gitalist::Git::Types qw/SHA1/;
+use MooseX::Types::Common::String qw/NonEmptySimpleStr/;
+use MooseX::Types::DateTime;
+use DateTime;
+
+has sha1        => ( isa      => SHA1,
+                     is       => 'ro',
+                     required => 1,
+                 );
+has name        => ( isa      => NonEmptySimpleStr,
+                     is       => 'ro',
+                     required => 1,
+                 );
+has committer   => ( isa      => NonEmptySimpleStr,
+                     is       => 'ro',
+                     required => 1,
+                 );
+has last_change => ( isa      => 'DateTime',
+                     is       => 'ro',
+                     required => 1,
+                     coerce   => 1,
+);
+
+around BUILDARGS => sub {
+    my $orig = shift;
+    my $class = shift;
+
+    if ( @_ == 1 && ! ref $_[0] ) {
+        my $line = $_[0];
+        # expects $line to match the output from
+        # for-each-ref --format=%(objectname)%00%(refname)%00%(committer)
+        my ($sha1, $name, $commitinfo) = split /\0/, $line, 3;
+        $name =~ s!^refs/heads/!!;
+
+        my ($committer, $epoch, $tz) =
+            $commitinfo =~ /(.*)\s(\d+)\s+([+-]\d+)$/;
+        my $dt = DateTime->from_epoch(
+            epoch => $epoch,
+            time_zone => $tz,
+        );
+
+        return $class->$orig(
+            sha1 => $sha1,
+            name => $name,
+            committer => $committer,
+            last_change => $dt,
+        );
+    } else {
+        return $class->$orig(@_);
+    }
+};
+
+1;
@@ -23,6 +23,23 @@ class Gitalist::Git::Object::Commit
                                       ],
                          );
 
+        method _build_tree {
+            return [$self->repository->get_object($self->tree_sha1)];
+        }
+
+        method sha_by_path ($path) {
+            $path =~ s{/+$}();
+            # FIXME should this really just take the first result?
+            my @paths = $self->repository->run_cmd('ls-tree', $self->sha1, '--', $path)
+                or return;
+            my $line = $paths[0];
+
+            #'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa	panic.c'
+            $line =~ m/^([0-9]+) (.+) ($SHA1RE)\t/;
+            my $sha1 = $3;
+            return $self->repository->get_object($sha1);
+    }
+
         method get_patch ( Maybe[NonEmptySimpleStr] $parent_hash?,
                            Int $patch_count?) {
             # assembling the git command to execute...
@@ -233,6 +250,10 @@ Subclass of C<Gitalist::Git::Object>.
 
 =head1 METHODS
 
+=head2 sha_by_path ($path)
+
+Returns the tree/file sha1 for a given path in a commit.
+
 =head2 get_patch
 
 =head2 diff
@@ -1,9 +1,10 @@
 use MooseX::Declare;
 use Moose::Autobox;
 
-class Gitalist::Git::Object {
+class Gitalist::Git::Object is dirty {
     use MooseX::Types::Moose qw/Str Int Bool Maybe ArrayRef/;
     use MooseX::Types::Common::String qw/NonEmptySimpleStr/;
+    use overload '""' => '_to_string', fallback => 1;
 
     # repository and sha1 are required initargs
     has repository => ( isa => 'Gitalist::Git::Repository',
@@ -50,6 +51,9 @@ class Gitalist::Git::Object {
     method BUILD { $self->$_() for qw/_gpp_obj size modestr/ }
 
 ## Private methods
+    method _to_string {
+        return $self->sha1;
+    };
 
 ## Builders
     method _build__gpp_obj {
@@ -15,6 +15,8 @@ class Gitalist::Git::Repository with Gitalist::Git::HasUtils {
     use Gitalist::Git::Object::Tree;
     use Gitalist::Git::Object::Commit;
     use Gitalist::Git::Object::Tag;
+    use Gitalist::Git::Head;
+    use Gitalist::Git::Tag;
 
     our $SHA1RE = qr/[0-9a-fA-F]{40}/;
 
@@ -23,7 +25,12 @@ class Gitalist::Git::Repository with Gitalist::Git::HasUtils {
         # Last path component becomes $self->name
         # Full path to git objects becomes $self->path
         my $name = $dir->dir_list(-1);
-        $dir = $dir->subdir('.git') if (-f $dir->file('.git', 'HEAD'));
+	if(-f $dir->file('.git', 'HEAD')) { # Non-bare repo above .git
+	    $dir  = $dir->subdir('.git');
+	    $name = $dir->dir_list(-2, 1); # .../name/.git
+	} elsif('.git' eq $dir->dir_list(-1)) { # Non-bare repo in .git
+	    $name = $dir->dir_list(-2);
+	}
         confess("Can't find a git repository at " . $dir)
             unless ( -f $dir->file('HEAD') );
         return $class->$orig(name => $name,
@@ -59,10 +66,10 @@ class Gitalist::Git::Repository with Gitalist::Git::HasUtils {
                              ? 1 : 0
                          },
                      );
-    has heads => ( isa => ArrayRef[HashRef],
+    has heads => ( isa => ArrayRef['Gitalist::Git::Head'],
                    is => 'ro',
                    lazy_build => 1);
-    has tags => ( isa => ArrayRef[HashRef],
+    has tags => ( isa => ArrayRef['Gitalist::Git::Tag'],
                    is => 'ro',
                    lazy_build => 1);
     has references => ( isa => HashRef[ArrayRef[Str]],
@@ -75,11 +82,6 @@ class Gitalist::Git::Repository with Gitalist::Git::HasUtils {
 
     ## Public methods
 
-    method get_object_or_head (NonEmptySimpleStr $ref) {
-        my $sha1 = is_SHA1($ref) ? $ref : $self->head_hash($ref);
-        $self->get_object($sha1);
-    }
-
     method head_hash (Str $head?) {
         my $output = $self->run_cmd(qw/rev-parse --verify/, $head || 'HEAD' );
         confess("No such head: " . $head) unless defined $output;
@@ -88,12 +90,6 @@ class Gitalist::Git::Repository with Gitalist::Git::HasUtils {
         return $sha1;
     }
 
-    method list_tree (SHA1 $sha1?) {
-        $sha1 ||= $self->head_hash;
-        my $object = $self->get_object($sha1);
-        return @{$object->tree};
-    }
-
     method get_object (NonEmptySimpleStr $sha1) {
         unless (is_SHA1($sha1)) {
             $sha1 = $self->head_hash($sha1);
@@ -108,20 +104,6 @@ class Gitalist::Git::Repository with Gitalist::Git::HasUtils {
         );
     }
 
-    method hash_by_path ($base, $path = '', $type?) {
-        $path =~ s{/+$}();
-        # FIXME should this really just take the first result?
-        my @paths = $self->run_cmd('ls-tree', $base, '--', $path)
-            or return;
-        my $line = $paths[0];
-
-        #'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa	panic.c'
-        $line =~ m/^([0-9]+) (.+) ($SHA1RE)\t/;
-        return defined $type && $type ne $2
-            ? ()
-                : $3;
-    }
-
     method list_revs ( NonEmptySimpleStr :$sha1!,
                        Int :$count?,
                        Int :$skip?,
@@ -262,19 +244,8 @@ class Gitalist::Git::Repository with Gitalist::Git::HasUtils {
         my @revlines = $self->run_cmd_list(qw/for-each-ref --sort=-committerdate /, '--format=%(objectname)%00%(refname)%00%(committer)', 'refs/heads');
         my @ret;
         for my $line (@revlines) {
-            my ($rev, $head, $commiter) = split /\0/, $line, 3;
-            $head =~ s!^refs/heads/!!;
-
-            push @ret, { sha1 => $rev, name => $head };
-
-            #FIXME: That isn't the time I'm looking for..
-            if (my ($epoch, $tz) = $line =~ /\s(\d+)\s+([+-]\d+)$/) {
-                my $dt = DateTime->from_epoch(epoch => $epoch);
-                $dt->set_time_zone($tz);
-                $ret[-1]->{last_change} = $dt;
-            }
+            push @ret, Gitalist::Git::Head->new($line);
         }
-
         return \@ret;
     }
 
@@ -286,21 +257,8 @@ class Gitalist::Git::Repository with Gitalist::Git::HasUtils {
         );
         my @ret;
         for my $line (@revlines) {
-            my($refinfo, $creatorinfo) = split /\0/, $line;
-            my($rev, $type, $name, $refid, $reftype, $title) = split(' ', $refinfo, 6);
-            my($creator, $epoch, $tz) = ($creatorinfo =~ /^(.*) ([0-9]+) (.*)$/);
-            $name =~ s!^refs/tags/!!;
-
-            push @ret, { sha1 => $rev, name => $name };
-
-            #FIXME: That isn't the time I'm looking for..
-            if($epoch and $tz) {
-                my $dt = DateTime->from_epoch(epoch => $epoch);
-                $dt->set_time_zone($tz);
-                $ret[-1]->{last_change} = $dt;
-            }
+            push @ret, Gitalist::Git::Tag->new($line);
         }
-
         return \@ret;
     }
 
@@ -391,20 +349,10 @@ Hashref of ArrayRefs for each reference.
 
 Return the sha1 for HEAD, or any specified head.
 
-=head2 list_tree ($sha1?)
-
-Return an array of contents for a given tree.
-The tree is specified by sha1, and defaults to HEAD.
-Each item is a L<Gitalist::Git::Object>.
-
 =head2 get_object ($sha1)
 
 Return an appropriate subclass of L<Gitalist::Git::Object> for the given sha1.
 
-=head2 hash_by_path ($sha1, $path, $type?)
-
-Returns the sha1 for a given path, optionally limited by type.
-
 =head2 list_revs ($sha1, $count?, $skip?, \%search?, $file?)
 
 Returns a list of revs for the given head ($sha1).
@@ -0,0 +1,79 @@
+package Gitalist::Git::Tag;
+use Moose;
+use namespace::autoclean;
+
+use Gitalist::Git::Types qw/SHA1/;
+use MooseX::Types::Common::String qw/NonEmptySimpleStr/;
+use MooseX::Types::Moose qw/Maybe Str/;
+use MooseX::Types::DateTime;
+use DateTime;
+
+has sha1        => ( isa      => SHA1,
+                     is       => 'ro',
+                     required => 1,
+                 );
+has name        => ( isa      => NonEmptySimpleStr,
+                     is       => 'ro',
+                     required => 1,
+                 );
+
+has type        => ( isa      => NonEmptySimpleStr,
+                     is       => 'ro',
+                     required => 1,
+                 );
+
+has ref_sha1    => ( isa      => Maybe[SHA1],
+                     is       => 'ro',
+                     required => 0,
+                 );
+has ref_type    => ( isa      => Maybe[NonEmptySimpleStr],
+                     is       => 'ro',
+                     required => 0,
+                 );
+has committer   => ( isa      => NonEmptySimpleStr,
+                     is       => 'ro',
+                     required => 1,
+                 );
+has last_change => ( isa      => 'DateTime',
+                     is       => 'ro',
+                     required => 1,
+                     coerce   => 1,
+);
+
+around BUILDARGS => sub {
+    my $orig = shift;
+    my $class = shift;
+
+    if ( @_ == 1 && ! ref $_[0] ) {
+        my $line = $_[0];
+        # expects $line to match the output from
+        # --format=%(objectname) %(objecttype) %(refname) %(*objectname) %(*objecttype) %(subject)%00%(creator)
+        my ($sha1, $type, $name, $ref_sha1, $ref_type, $rest) = split / /, $line, 6;
+        $name =~ s!^refs/tags/!!;
+
+        unless ($ref_sha1) {
+            ($ref_sha1, $ref_type) = (undef, undef);
+        }
+        my ($subject, $commitinfo) = split /\0/, $rest, 2;
+        my ($committer, $epoch, $tz) =
+            $commitinfo =~ /(.*)\s(\d+)\s+([+-]\d+)$/;
+        my $dt = DateTime->from_epoch(
+            epoch => $epoch,
+            time_zone => $tz,
+        );
+
+        return $class->$orig(
+            sha1 => $sha1,
+            name => $name,
+            type => $type,
+            committer => $committer,
+            last_change => $dt,
+            ref_sha1 => $ref_sha1,
+            ref_type => $ref_type,
+        );
+    } else {
+        return $class->$orig(@_);
+    }
+};
+
+1;
@@ -1,7 +1,7 @@
 package Gitalist::Model::CollectionOfRepos;
 
 use Moose;
-use Gitalist::Git::CollectionOfRepositories::FromDirectory;
+use Gitalist::Git::CollectionOfRepositories::FromDirectoryRecursive;
 use Gitalist::Git::CollectionOfRepositories::FromListOfDirectories;
 use MooseX::Types::Moose qw/Maybe ArrayRef/;
 use MooseX::Types::Common::String qw/NonEmptySimpleStr/;
@@ -71,7 +71,7 @@ sub build_per_context_instance {
         Gitalist::Git::CollectionOfRepositories::FromListOfDirectories->new(repos => $self->repos);
     }
     else {
-        Gitalist::Git::CollectionOfRepositories::FromDirectory->new(repo_dir => $self->repo_dir);
+        Gitalist::Git::CollectionOfRepositories::FromDirectoryRecursive->new(repo_dir => $self->repo_dir);
     }
 }
 
@@ -20,7 +20,7 @@ after 'base' => sub {
 sub find : Chained('base') PathPart('') CaptureArgs(1) {
     my ($self, $c, $sha1part) = @_;
     # FIXME - Should not be here!
-    $c->stash->{Commit} = $c->stash->{Repository}->get_object_or_head($sha1part)
+    $c->stash->{Commit} = $c->stash->{Repository}->get_object($sha1part)
         or $c->detach('/error404', "Couldn't find a object for '$sha1part' in XXXX!");
     $c->stash->{data} = $c->stash->{Commit};
 }
@@ -34,7 +34,7 @@ sub _set_diff_args {
     $c->stash(parent   => shift @rest)
         if @rest == 2
         # Check that the single arg is unlikely to be a path.
-        or @rest && to_SHA1($rest[0]) && $c->stash->{Repository}->get_object_or_head($rest[0]);
+        or @rest && to_SHA1($rest[0]) && $c->stash->{Repository}->get_object($rest[0]);
     $c->stash(filename => $rest[-1])
       if @rest;
 }
@@ -63,15 +63,20 @@ sub tree : Chained('find') Does('FilenameArgs') Args() {}
 sub find_blob : Action {
     my ($self, $c) = @_;
     my($repo, $object) = @{$c->{stash}}{qw(Repository Commit)};
+
     # FIXME - Eugh!
-    my $h  = $object->isa('Gitalist::Git::Object::Commit')
-           ? $repo->hash_by_path($object->sha1, $c->stash->{filename})
-           : $object->isa('Gitalist::Git::Object::Blob')
-             ? $object->sha1
-             : die "Unknown object type for '${\$object->sha1}'";
+    my $blob;
+    if ($object->isa('Gitalist::Git::Object::Commit')) {
+        $blob = $object->sha_by_path($c->stash->{filename});
+    } elsif ($object->isa('Gitalist::Git::Object::Blob')) {
+        $blob = $object;
+    } else {
+        die "Unknown object type for '${\$object->sha1}'";
+    }
     die "No file or sha1 provided."
-        unless $h;
-    $c->stash(blob => $repo->get_object($h)->content);
+        unless $blob;
+
+    $c->stash(blob => $blob->content);
 }
 
 sub blob : Chained('find') Does('FilenameArgs') Args() {
@@ -14,7 +14,7 @@ use Catalyst qw/
                 SubRequest
 /;
 
-our $VERSION = '0.002006';
+our $VERSION = '0.002007';
 $VERSION = eval $VERSION;
 
 __PACKAGE__->config(
@@ -60,6 +60,8 @@ sub uri_with {
 
 __END__
 
+=encoding UTF-8
+
 =head1 NAME
 
 Gitalist - A modern git web viewer
@@ -71,7 +73,7 @@ Gitalist - A modern git web viewer
 =head1 INSTALL
 
 As Gitalist follows the usual Perl module format the usual approach
-for installation should work e.g.
+for installation should work, e.g.:
 
   perl Makefile.PL
   make
@@ -82,20 +84,22 @@ or
 
   cpan -i Gitalist
 
-You can also check gitalist out from git and run it, in this case you'll additionally
-need the author modules, but no configuration will be needed as it will default to looking
+You can also L<check Gitalist out from its git repository|/"GETTING GITALIST">
+and run it, in this case you'll additionally need the author modules,
+but no configuration will be needed as it will default to looking
 for repositories the directory above the checkout.
 
 =head1 DESCRIPTION
 
-Gitalist is a web frontend for git repositories based on gitweb.cgi
-and backed by Catalyst.
+Gitalist is a web frontend for git repositories based on
+L<gitweb.cgi|https://git.wiki.kernel.org/index.php/Gitweb> and backed by
+L<Catalyst>.
 
 =head2 History
 
-This project started off as an attempt to port gitweb.cgi to a
+This project started off as an attempt to port I<gitweb.cgi> to a
 Catalyst app in a piecemeal fashion. As it turns out, thanks largely
-to Florian Ragwitz's earlier effort, it was easier to use gitweb.cgi
+to Florian Ragwitz's earlier effort, it was easier to use I<gitweb.cgi>
 as a template for building a new Catalyst application.
 
 =head1 GETTING GITALIST
@@ -110,7 +114,8 @@ The canonical repository for the master branch is:
 
     git://git.shadowcat.co.uk/catagits/Gitalist.git
 
-Gitalist is also mirrored to github, and a number of people have active forks
+Gitalist is also mirrored to GitHub at L<https://github.com/broquaint/Gitalist>,
+and a number of people have active forks
 with branches and/or new features in the master branch.
 
 =head1 BOOTSTRAPPING
@@ -120,10 +125,10 @@ own directory by installing its prerequisites locally with the help of
 L<local::lib>. So instead of installing the prerequisites to the
 system path with CPAN they are installed under the Gitalist directory.
 
-To do this clone Gitalist from the Shadowcat repository mentioned
-above or grab a snapshot from broquaint's github repository:
+To do this clone Gitalist from the L<Shadowcat repository mentioned
+above|/"GETTING GITALIST"> or grab a snapshot from broquaint's GitHub repository:
 
-    http://github.com/broquaint/Gitalist/downloads
+    https://github.com/broquaint/Gitalist/downloads
 
 With the source acquired and unpacked run the following from within the
 Gitalist directory:
@@ -133,7 +138,7 @@ Gitalist directory:
 This will install the necessary modules for the build process which in
 turn installs the prerequisites locally.
 
-I<NB> The relevant bootstrap scripts aren't available in the CPAN dist
+B<NB:> The relevant bootstrap scripts aren't available in the CPAN dist
 as the bootstrap scripts should not be installed.
 
 =head1 INITIAL CONFIGURATION
@@ -164,7 +169,8 @@ by running:
 
   cp `perl -Ilib -MGitalist -e'print Gitalist->path_to("gitalist.conf")'` gitalist.conf
 
-You can then edit this confg, adding a repo_dir path and customising other settings as desired.
+You can then edit this configuration, adding a C<repo_dir> path and customising
+other settings as desired.
 
 You can then start the Gitalist demo server by setting C<< GITALIST_CONFIG >>. For example:
 
@@ -187,7 +193,7 @@ to run it in a more production facing environment than using the single threaded
 server.
 
 The recommended deployment method for Gitalist is FastCGI, although Gitalist can also be run
-under mod_perl or as pure perl with L<Catalyst::Engine::PreFork>.
+under L<mod_perl|https://perl.apache.org/> or as pure Perl with L<Catalyst::Engine::PreFork>.
 
 Assuming that you have installed Gitalist's dependencies into a L<local::lib>, and you
 are running from a git checkout, adding a trivial FCGI script as C<script/gitalist.fcgi>
@@ -199,45 +205,50 @@ are running from a git checkout, adding a trivial FCGI script as C<script/gitali
 This example can be seen live here:
 
     http://example.gitalist.com
-    
+
 =head2 FASTCGI
-        Running Gitalist in FastCGI mode requires a webserver with FastCGI
-        support (such as apache with mod_fcgi or fcgid). Below is a sample 
-        configuration using Apache2 with fcgid in a dynamic configuration
-        (as opposed to static or standalone mode). More information on these modes and 
-        their configuration can be found at 
-        http://search.cpan.org/~bobtfish/Catalyst-Runtime-5.80025/lib/Catalyst/Engine/FastCGI.pm#Standalone_server_mode
-			
-        In Apache's mime.conf, add AddHandler fcgid-script .fcgi (or AddHandler fastcgi-script .fcgi for mod_fcgi)
-			
-        And a quick VirtualHost configuration:
-			
-        <VirtualHost *:80>
-          ServerName gitalist.yourdomain.com
-          DocumentRoot /path/to/gitalist.fcgi
-          <Directory "/path/to/gitalist.fcgi">
+
+Running Gitalist in FastCGI mode requires a webserver with FastCGI
+support (such as apache with L<mod_fcgi|http://www.fastcgi.com/drupal/node/3>
+or L<mod_fcgid|https://httpd.apache.org/mod_fcgid/>). Below is a sample
+configuration using Apache2 with mod_fcgid in a dynamic configuration
+(as opposed to static or standalone mode). More information on these modes and
+their configuration can be found at L<Catalyst::Engine::FastCGI/"Standalone server mode">.
+
+In Apache's F<mime.conf>, add C<AddHandler fcgid-script .fcgi>
+(or C<AddHandler fastcgi-script .fcgi> for mod_fcgi).
+
+And a quick VirtualHost configuration:
+
+    <VirtualHost *:80>
+        ServerName gitalist.yourdomain.com
+        DocumentRoot /path/to/gitalist.fcgi
+        <Directory "/path/to/gitalist.fcgi">
             AllowOverride all
             Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
             Order allow,deny
             Allow from all
-          </Directory>
+        </Directory>
 
         # Tell Apache this is a FastCGI application
         <Files gitalist.fcgi>
             #change the below to fastcgi-script if using mod_fcgi
             SetHandler fcgid-script
         </Files>
-      </VirtualHost>
-			
-        Now to access your gitalist instance, you'll go to gitalist.yourdomain.com/gitalist.fcgi/ 
-        (DO NOT FORGET THAT TRAILING /). If you'd like a different URL, of course, you'll likely want to use 
-        mod_rewrite or equivalent
-			
-        If you find the need to do some troubleshooting, you can call http://url_to_gitalist.fcgi?dump_info=1
-        and/or add export GITALIST_DEBUG=1 to the top of you gitalist.fcgi file (just below the shebang line).
-		
-        Also, note that  Apache will refuse %2F in Gitalist URL's unless configured otherwise. Make sure
-        "AllowEncodedSlashes On" is in your httpd.conf file in order for this to run smoothly.
+    </VirtualHost>
+
+Now to access your Gitalist instance, you'll go to
+C<gitalist.yourdomain.com/gitalist.fcgi/> (B<do not forget that trailing> C</>).
+If you'd like a different URL, of course, you'll likely want to use
+L<mod_rewrite|https://httpd.apache.org/docs/mod/mod_rewrite.html> or equivalent.
+
+If you find the need to do some troubleshooting, you can call
+C<http://url_to_gitalist.fcgi?dump_info=1> and/or add export C<GITALIST_DEBUG=1>
+to the top of your F<gitalist.fcgi> file (just below the shebang line).
+
+Also, note that Apache will refuse C<%2F> in Gitalist URLs
+unless configured otherwise. Make sure C<AllowEncodedSlashes On>
+is in your F<httpd.conf> file in order for this to run smoothly.
 
 
 =head1 CONTRIBUTING
@@ -263,19 +274,17 @@ L<Catalyst>
 =head1 AUTHORS AND COPYRIGHT
 
   Catalyst application:
-    (C) 2009 Venda Ltd and Dan Brook <broq@cpan.org>
-    (C) 2009, Tom Doran <bobtfish@bobtfish.net>
-    (C) 2009, Zac Stevens <zts@cryptocracy.com>
+    © 2009 Venda Ltd and Dan Brook <broq@cpan.org>
+    © 2009, Tom Doran <bobtfish@bobtfish.net>
+    © 2009, Zac Stevens <zts@cryptocracy.com>
 
   Original gitweb.cgi from which this was derived:
-    (C) 2005-2006, Kay Sievers <kay.sievers@vrfy.org>
-    (C) 2005, Christian Gierke
+    © 2005-2006, Kay Sievers <kay.sievers@vrfy.org>
+    © 2005, Christian Gierke
 
   Model based on http://github.com/rafl/gitweb
-    (C) 2008, Florian Ragwitz
+    © 2008, Florian Ragwitz
 
 =head1 LICENSE
 
 Licensed under GNU GPL v2
-
-=cut
diff --git a/var/tmp/source/BROQ/Gitalist-0.002007/Gitalist-0.002007/root/favicon_gif.ico b/var/tmp/source/BROQ/Gitalist-0.002007/Gitalist-0.002007/root/favicon_gif.ico
new file mode 100755
index 00000000..fea2fec4
Binary files /dev/null and b/var/tmp/source/BROQ/Gitalist-0.002007/Gitalist-0.002007/root/favicon_gif.ico differ
@@ -1,7 +1,7 @@
 #!/usr/bin/env perl
 use FindBin qw/$Bin/;
 BEGIN {
-    my $env = "$FindBin::Bin/script/env";
+    my $env = "$FindBin::Bin/../script/env";
     if (-r $env) {
         do $env or die $@;
     }
@@ -1,6 +1,6 @@
 use FindBin qw/$Bin/;
 BEGIN {
-    my $env = "$FindBin::Bin/script/env";
+    my $env = "$FindBin::Bin/../script/env";
     if (-r $env) {
         do $env or die $@;
     }
@@ -0,0 +1,55 @@
+use FindBin qw/$Bin/;
+BEGIN {
+    my $env = "$FindBin::Bin/../script/env";
+    if (-r $env) {
+        do $env or die $@;
+    }
+}
+
+use strict;
+use warnings;
+use Test::More qw/no_plan/;
+use Test::Exception;
+use Path::Class::Dir;
+
+BEGIN { use_ok 'Gitalist::Git::CollectionOfRepositories::FromDirectoryRecursive' }
+
+my $repo_dir = "$Bin/lib/repositories";
+my $repo = Gitalist::Git::CollectionOfRepositories::FromDirectoryRecursive->new( repo_dir => $repo_dir );
+isa_ok($repo, 'Gitalist::Git::CollectionOfRepositories::FromDirectoryRecursive');
+
+is($repo->repo_dir, $repo_dir, "repo->repo_dir is correct" );
+
+# 'bare.git' is a bare git repository in the repository dir
+
+my $repository_list = $repo->repositories;
+is( scalar @{$repository_list}, 5, '->repositories is an array with the correct number of members' );
+isa_ok($repository_list->[0], 'Gitalist::Git::Repository');
+my @sorted_names = sort map { $_->{name} } @{$repository_list};
+is_deeply( \@sorted_names, [ qw( bare.git barerecursive.git nodescription repo1 scratch.git) ], 'Repositories are correctly loaded' );
+
+dies_ok {
+  my $repository = $repo->get_repository("NoSuchRepository");
+} 'throws exception for invalid repository';
+
+dies_ok {
+  my $repository = $repo->get_repository();
+} 'throws exception for no repository';
+
+dies_ok {
+  my $repository = $repo->get_repository('../../../');
+} 'Relative directory not contained within repo_dir';
+
+my $repository = $repo->get_repository( "repo1" );
+isa_ok($repository, 'Gitalist::Git::Repository');
+
+$repository = $repo->get_repository( "scratch.git" );
+isa_ok($repository, 'Gitalist::Git::Repository');
+
+# check for bug where get_repository blew up if repo_dir
+# was a relative path
+lives_ok {
+  my $repo2_dir = "$Bin/lib/../lib/repositories";
+  my $repo2 = Gitalist::Git::CollectionOfRepositories::FromDirectoryRecursive->new( repo_dir => $repo2_dir );
+  my $repo2_proj = $repo2->get_repository("repo1");
+} 'relative repo_dir properly handled';
@@ -1,6 +1,6 @@
 use FindBin qw/$Bin/;
 BEGIN {
-    my $env = "$FindBin::Bin/script/env";
+    my $env = "$FindBin::Bin/../script/env";
     if (-r $env) {
         do $env or die $@;
     }
@@ -50,34 +50,31 @@ ok(keys %references >= 2, '->references hash has elements');
 is($references{'36c6c6708b8360d7023e8a1649c45bcf9b3bd818'}->[0], 'heads/master', 'reference looks ok');
 my @heads = @{$proj->heads};
 ok(scalar @heads > 1, '->heads list has more than one element');
-my %head = %{$heads[1]};
-ok(keys %head == 3, '->heads[1] has the right number of keys');
-ok(defined $head{sha1}, '->heads[1]-sha1 is defined');
-ok(defined $head{name}, '->heads[1]-name is defined');
+my $head = $heads[1];
+isa_ok($head, 'Gitalist::Git::Head');
 is($proj->head_hash, '36c6c6708b8360d7023e8a1649c45bcf9b3bd818', 'head_hash for HEAD is correct');
 is($proj->head_hash('refs/heads/master'), '36c6c6708b8360d7023e8a1649c45bcf9b3bd818', 'head_hash for refs/heads/master is correct');
 is($proj->head_hash('rafs/head/mister'), undef, 'head_hash for rafs/head/mister is undef');
 
-is(scalar $proj->list_tree, 2, 'expected number of entries in tree');
-isa_ok(($proj->list_tree)[1], 'Gitalist::Git::Object');
+ok(scalar @{$proj->tags} == 1, '->tags list has one element');
 
 # Return an ::Object from a sha1
 my $obj1 = $proj->get_object('729a7c3f6ba5453b42d16a43692205f67fb23bc1');
 isa_ok($obj1, 'Gitalist::Git::Object::Tree');
 
-my $hbp_sha1 = $proj->hash_by_path('36c6c6708b8360d7023e8a1649c45bcf9b3bd818', 'dir1/file2');
-my $obj2 = $proj->get_object($hbp_sha1);
-isa_ok($obj2, 'Gitalist::Git::Object::Blob');
-is($obj2->type, 'blob', 'hash_by_path obj is a file');
-is($obj2->content, "foo\n", 'hash_by_path obj is a file');
-
 my $obj3 = $proj->get_object($proj->head_hash);
 isa_ok($obj3, 'Gitalist::Git::Object::Commit');
 
+my $obj2 = $obj3->sha_by_path('dir1/file2');
+isa_ok($obj2, 'Gitalist::Git::Object::Blob');
+is($obj2->type, 'blob', 'sha_by_path obj is a blob');
+is($obj2->content, "foo\n", 'sha_by_path obj content is correct');
+
+
 like($proj->head_hash('HEAD'), qr/^([0-9a-fA-F]{40})$/, 'head_hash');
 
 {
-    my @tree = $proj->list_tree('3bc0634310b9c62222bb0e724c11ffdfb297b4ac');
+    my @tree = @{$obj3->tree};
     is(scalar @tree, 1, "tree array contains one entry.");
     isa_ok($tree[0], 'Gitalist::Git::Object', 'tree element 0');
 }
@@ -0,0 +1,35 @@
+use FindBin qw/$Bin/;
+BEGIN {
+    my $env = "$FindBin::Bin/../script/env";
+    if (-r $env) {
+        do $env or die $@;
+    }
+}
+
+use strict;
+use warnings;
+use Test::More qw/no_plan/;
+use Test::Exception;
+use Data::Dumper;
+
+BEGIN { use_ok 'Gitalist::Git::Head' }
+
+
+my $revline="a92fb1c9282f7319099ce7f783c8be7d5360f6e3\0refs/heads/model-cleanup\0Zachary Stevens <zts\@cryptocracy.com> 1277601094 +0100";
+my $instance = Gitalist::Git::Head->new($revline);
+isa_ok($instance, 'Gitalist::Git::Head');
+
+# Create an instance, passing last_change as a DateTime
+use DateTime;
+my $timespec = [1277578462, '+0100'];
+my $dt = DateTime->from_epoch(
+    epoch => @$timespec[0],
+    time_zone => @$timespec[1],
+);
+my $head = Gitalist::Git::Head->new(
+    sha1 => 'bca1153c22e393a952b6715bf2212901e4e77215',
+    name => 'master',
+    committer => 'Zachary Stevens <zts@cryptocracy.com>',
+    last_change => $dt,
+);
+isa_ok($head, 'Gitalist::Git::Head');
@@ -1,6 +1,6 @@
 use FindBin qw/$Bin/;
 BEGIN {
-    my $env = "$FindBin::Bin/script/env";
+    my $env = "$FindBin::Bin/../script/env";
     if (-r $env) {
         do $env or die $@;
     }
@@ -39,6 +39,7 @@ is($object->file, 'dir1', 'file is correct');
 is($object->mode, 16384, 'mode is correct');
 is($object->modestr, 'drwxr-xr-x', "modestr is correct" );
 is($object->size, 33, "size is correct");
+is($object,'729a7c3f6ba5453b42d16a43692205f67fb23bc1', 'stringifies correctly');
 
 # Create object from sha1.
 my $obj2 = Gitalist::Git::Object::Blob->new(
@@ -64,6 +65,7 @@ my $commit_obj = Gitalist::Git::Object::Commit->new(
     sha1 => '3f7567c7bdf7e7ebf410926493b92d398333116e',
 );
 isa_ok($commit_obj, 'Gitalist::Git::Object::Commit', "commit object");
+isa_ok($commit_obj->tree->[0], 'Gitalist::Git::Object::Tree');
 my ($tree, $patch) = $commit_obj->diff(
     patch => 1,
 );
@@ -0,0 +1,36 @@
+use FindBin qw/$Bin/;
+BEGIN {
+    my $env = "$FindBin::Bin/../script/env";
+    if (-r $env) {
+        do $env or die $@;
+    }
+}
+use strict;
+use warnings;
+use Test::More qw/no_plan/;
+use Test::Exception;
+use Data::Dumper;
+
+BEGIN { use_ok 'Gitalist::Git::Tag' }
+
+# Create an instance from for-each-ref output
+my $revline="36c6c6708b8360d7023e8a1649c45bcf9b3bd818 commit refs/tags/0.01   add dir1/file2\0Florian Ragwitz <rafl\@debian.org> 1173210275 +0100";
+#my $revline="a92fb1c9282f7319099ce7f783c8be7d5360f6e3\0refs/heads/model-cleanup\0Zachary Stevens <zts\@cryptocracy.com> 1277601094 +0100";
+my $instance = Gitalist::Git::Tag->new($revline);
+isa_ok($instance, 'Gitalist::Git::Tag');
+
+# Create an instance, passing last_change as a DateTime
+use DateTime;
+my $timespec = [1173210275, '+0100'];
+my $dt = DateTime->from_epoch(
+    epoch => @$timespec[0],
+    time_zone => @$timespec[1],
+);
+my $head = Gitalist::Git::Tag->new(
+    sha1 => '36c6c6708b8360d7023e8a1649c45bcf9b3bd818',
+    name => '0.01',
+    type => 'commit',
+    committer => 'Florian Ragwitz <rafl@debian.org>',
+    last_change => $dt,
+);
+isa_ok($head, 'Gitalist::Git::Tag');
@@ -1,6 +1,6 @@
 use FindBin qw/$Bin/;
 BEGIN {
-    my $env = "$FindBin::Bin/script/env";
+    my $env = "$FindBin::Bin/../script/env";
     if (-r $env) {
         do $env or die $@;
     }
@@ -1,7 +1,7 @@
 #!/usr/bin/env perl
 use FindBin qw/$Bin/;
 BEGIN {
-    my $env = "$FindBin::Bin/script/env";
+    my $env = "$FindBin::Bin/../script/env";
     if (-r $env) {
         do $env or die $@;
     }
@@ -1,7 +1,7 @@
 #!/usr/bin/env perl
 use FindBin qw/$Bin/;
 BEGIN {
-    my $env = "$FindBin::Bin/script/env";
+    my $env = "$FindBin::Bin/../script/env";
     if (-r $env) {
         do $env or die $@;
     }
@@ -1,7 +1,7 @@
 #!/usr/bin/env perl
 use FindBin qw/$Bin/;
 BEGIN {
-    my $env = "$FindBin::Bin/script/env";
+    my $env = "$FindBin::Bin/../script/env";
     if (-r $env) {
         do $env or die $@;
     }
@@ -1,3 +1,10 @@
+use FindBin qw/$Bin/;
+BEGIN {
+    my $env = "$FindBin::Bin/../../script/env";
+    if (-r $env) {
+        do $env or die $@;
+    }
+}
 use Test::NoTabs;
 all_perl_files_ok(qw(t lib));
 
@@ -1,8 +1,16 @@
 #!/usr/bin/env perl
+use FindBin qw/$Bin/;
+BEGIN {
+    my $env = "$FindBin::Bin/../../script/env";
+    if (-r $env) {
+        do $env or die $@;
+    }
+}
+
 use strict;
 use warnings;
 use Test::More;
 
 use Test::Pod 1.14;
 
-all_pod_files_ok();
+all_pod_files_ok( all_pod_files('lib') );
@@ -1,14 +1,21 @@
-#!/usr/bin/env perl
+use FindBin qw/$Bin/;
+BEGIN {
+    my $env = "$FindBin::Bin/../../script/env";
+    if (-r $env) {
+        do $env or die $@;
+    }
+}
+
 use strict;
 use warnings;
 use Test::More;
 
 use Test::Pod::Coverage 1.04;
 
-all_pod_coverage_ok({
+pod_coverage_ok($_,  {
     also_private => [qw/
         BUILD
         BUILDARGS
         build_per_context_instance
     /],
-});
+}) for all_modules('lib');
@@ -0,0 +1 @@
+ref: refs/heads/master
@@ -0,0 +1,7 @@
+[core]
+	repositoryformatversion = 0
+	filemode = true
+	bare = true
+	sharedrepository = 1
+[receive]
+	denyNonFastforwards = true
@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.
@@ -0,0 +1,15 @@
+#!/bin/sh
+#
+# An example hook script to check the commit log message taken by
+# applypatch from an e-mail message.
+#
+# The hook should exit with non-zero status after issuing an
+# appropriate message if it wants to stop the commit.  The hook is
+# allowed to edit the commit message file.
+#
+# To enable this hook, rename this file to "applypatch-msg".
+
+. git-sh-setup
+test -x "$GIT_DIR/hooks/commit-msg" &&
+	exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"}
+:
@@ -0,0 +1,24 @@
+#!/bin/sh
+#
+# An example hook script to check the commit log message.
+# Called by git-commit with one argument, the name of the file
+# that has the commit message.  The hook should exit with non-zero
+# status after issuing an appropriate message if it wants to stop the
+# commit.  The hook is allowed to edit the commit message file.
+#
+# To enable this hook, rename this file to "commit-msg".
+
+# Uncomment the below to add a Signed-off-by line to the message.
+# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
+# hook is more suited to it.
+#
+# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
+# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
+
+# This example catches duplicate Signed-off-by lines.
+
+test "" = "$(grep '^Signed-off-by: ' "$1" |
+	 sort | uniq -c | sed -e '/^[ 	]*1[ 	]/d')" || {
+	echo >&2 Duplicate Signed-off-by lines.
+	exit 1
+}
@@ -0,0 +1,8 @@
+#!/bin/sh
+#
+# An example hook script that is called after a successful
+# commit is made.
+#
+# To enable this hook, rename this file to "post-commit".
+
+: Nothing
@@ -0,0 +1,15 @@
+#!/bin/sh
+#
+# An example hook script for the "post-receive" event.
+#
+# The "post-receive" script is run after receive-pack has accepted a pack
+# and the repository has been updated.  It is passed arguments in through
+# stdin in the form
+#  <oldrev> <newrev> <refname>
+# For example:
+#  aa453216d1b3e49e7f6f98441fa56946ddcd6a20 68f7abf4e6f922807889f52bc043ecd31b79f814 refs/heads/master
+#
+# see contrib/hooks/ for a sample, or uncomment the next line and
+# rename the file to "post-receive".
+
+#. /usr/share/doc/git-core/contrib/hooks/post-receive-email
@@ -0,0 +1,8 @@
+#!/bin/sh
+#
+# An example hook script to prepare a packed repository for use over
+# dumb transports.
+#
+# To enable this hook, rename this file to "post-update".
+
+exec git-update-server-info
@@ -0,0 +1,14 @@
+#!/bin/sh
+#
+# An example hook script to verify what is about to be committed
+# by applypatch from an e-mail message.
+#
+# The hook should exit with non-zero status after issuing an
+# appropriate message if it wants to stop the commit.
+#
+# To enable this hook, rename this file to "pre-applypatch".
+
+. git-sh-setup
+test -x "$GIT_DIR/hooks/pre-commit" &&
+	exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"}
+:
@@ -0,0 +1,46 @@
+#!/bin/sh
+#
+# An example hook script to verify what is about to be committed.
+# Called by git-commit with no arguments.  The hook should
+# exit with non-zero status after issuing an appropriate message if
+# it wants to stop the commit.
+#
+# To enable this hook, rename this file to "pre-commit".
+
+if git-rev-parse --verify HEAD >/dev/null 2>&1
+then
+	against=HEAD
+else
+	# Initial commit: diff against an empty tree object
+	against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
+fi
+
+# If you want to allow non-ascii filenames set this variable to true.
+allownonascii=$(git config hooks.allownonascii)
+
+# Cross platform projects tend to avoid non-ascii filenames; prevent
+# them from being added to the repository. We exploit the fact that the
+# printable range starts at the space character and ends with tilde.
+if [ "$allownonascii" != "true" ] &&
+	# Note that the use of brackets around a tr range is ok here, (it's
+	# even required, for portability to Solaris 10's /usr/bin/tr), since
+	# the square bracket bytes happen to fall in the designated range.
+	test "$(git diff --cached --name-only --diff-filter=A -z $against |
+	  LC_ALL=C tr -d '[ -~]\0')"
+then
+	echo "Error: Attempt to add a non-ascii file name."
+	echo
+	echo "This can cause problems if you want to work"
+	echo "with people on other platforms."
+	echo
+	echo "To be portable it is advisable to rename the file ..."
+	echo
+	echo "If you know what you are doing you can disable this"
+	echo "check using:"
+	echo
+	echo "  git config hooks.allownonascii true"
+	echo
+	exit 1
+fi
+
+exec git diff-index --check --cached $against --
@@ -0,0 +1,169 @@
+#!/bin/sh
+#
+# Copyright (c) 2006, 2008 Junio C Hamano
+#
+# The "pre-rebase" hook is run just before "git-rebase" starts doing
+# its job, and can prevent the command from running by exiting with
+# non-zero status.
+#
+# The hook is called with the following parameters:
+#
+# $1 -- the upstream the series was forked from.
+# $2 -- the branch being rebased (or empty when rebasing the current branch).
+#
+# This sample shows how to prevent topic branches that are already
+# merged to 'next' branch from getting rebased, because allowing it
+# would result in rebasing already published history.
+
+publish=next
+basebranch="$1"
+if test "$#" = 2
+then
+	topic="refs/heads/$2"
+else
+	topic=`git symbolic-ref HEAD` ||
+	exit 0 ;# we do not interrupt rebasing detached HEAD
+fi
+
+case "$topic" in
+refs/heads/??/*)
+	;;
+*)
+	exit 0 ;# we do not interrupt others.
+	;;
+esac
+
+# Now we are dealing with a topic branch being rebased
+# on top of master.  Is it OK to rebase it?
+
+# Does the topic really exist?
+git show-ref -q "$topic" || {
+	echo >&2 "No such branch $topic"
+	exit 1
+}
+
+# Is topic fully merged to master?
+not_in_master=`git-rev-list --pretty=oneline ^master "$topic"`
+if test -z "$not_in_master"
+then
+	echo >&2 "$topic is fully merged to master; better remove it."
+	exit 1 ;# we could allow it, but there is no point.
+fi
+
+# Is topic ever merged to next?  If so you should not be rebasing it.
+only_next_1=`git-rev-list ^master "^$topic" ${publish} | sort`
+only_next_2=`git-rev-list ^master           ${publish} | sort`
+if test "$only_next_1" = "$only_next_2"
+then
+	not_in_topic=`git-rev-list "^$topic" master`
+	if test -z "$not_in_topic"
+	then
+		echo >&2 "$topic is already up-to-date with master"
+		exit 1 ;# we could allow it, but there is no point.
+	else
+		exit 0
+	fi
+else
+	not_in_next=`git-rev-list --pretty=oneline ^${publish} "$topic"`
+	perl -e '
+		my $topic = $ARGV[0];
+		my $msg = "* $topic has commits already merged to public branch:\n";
+		my (%not_in_next) = map {
+			/^([0-9a-f]+) /;
+			($1 => 1);
+		} split(/\n/, $ARGV[1]);
+		for my $elem (map {
+				/^([0-9a-f]+) (.*)$/;
+				[$1 => $2];
+			} split(/\n/, $ARGV[2])) {
+			if (!exists $not_in_next{$elem->[0]}) {
+				if ($msg) {
+					print STDERR $msg;
+					undef $msg;
+				}
+				print STDERR " $elem->[1]\n";
+			}
+		}
+	' "$topic" "$not_in_next" "$not_in_master"
+	exit 1
+fi
+
+exit 0
+
+################################################################
+
+This sample hook safeguards topic branches that have been
+published from being rewound.
+
+The workflow assumed here is:
+
+ * Once a topic branch forks from "master", "master" is never
+   merged into it again (either directly or indirectly).
+
+ * Once a topic branch is fully cooked and merged into "master",
+   it is deleted.  If you need to build on top of it to correct
+   earlier mistakes, a new topic branch is created by forking at
+   the tip of the "master".  This is not strictly necessary, but
+   it makes it easier to keep your history simple.
+
+ * Whenever you need to test or publish your changes to topic
+   branches, merge them into "next" branch.
+
+The script, being an example, hardcodes the publish branch name
+to be "next", but it is trivial to make it configurable via
+$GIT_DIR/config mechanism.
+
+With this workflow, you would want to know:
+
+(1) ... if a topic branch has ever been merged to "next".  Young
+    topic branches can have stupid mistakes you would rather
+    clean up before publishing, and things that have not been
+    merged into other branches can be easily rebased without
+    affecting other people.  But once it is published, you would
+    not want to rewind it.
+
+(2) ... if a topic branch has been fully merged to "master".
+    Then you can delete it.  More importantly, you should not
+    build on top of it -- other people may already want to
+    change things related to the topic as patches against your
+    "master", so if you need further changes, it is better to
+    fork the topic (perhaps with the same name) afresh from the
+    tip of "master".
+
+Let's look at this example:
+
+		   o---o---o---o---o---o---o---o---o---o "next"
+		  /       /           /           /
+		 /   a---a---b A     /           /
+		/   /               /           /
+	       /   /   c---c---c---c B         /
+	      /   /   /             \         /
+	     /   /   /   b---b C     \       /
+	    /   /   /   /             \     /
+    ---o---o---o---o---o---o---o---o---o---o---o "master"
+
+
+A, B and C are topic branches.
+
+ * A has one fix since it was merged up to "next".
+
+ * B has finished.  It has been fully merged up to "master" and "next",
+   and is ready to be deleted.
+
+ * C has not merged to "next" at all.
+
+We would want to allow C to be rebased, refuse A, and encourage
+B to be deleted.
+
+To compute (1):
+
+	git-rev-list ^master ^topic next
+	git-rev-list ^master        next
+
+	if these match, topic has not merged in next at all.
+
+To compute (2):
+
+	git-rev-list master..topic
+
+	if this is empty, it is fully merged to "master".
@@ -0,0 +1,36 @@
+#!/bin/sh
+#
+# An example hook script to prepare the commit log message.
+# Called by git-commit with the name of the file that has the
+# commit message, followed by the description of the commit
+# message's source.  The hook's purpose is to edit the commit
+# message file.  If the hook fails with a non-zero status,
+# the commit is aborted.
+#
+# To enable this hook, rename this file to "prepare-commit-msg".
+
+# This hook includes three examples.  The first comments out the
+# "Conflicts:" part of a merge commit.
+#
+# The second includes the output of "git diff --name-status -r"
+# into the message, just before the "git status" output.  It is
+# commented because it doesn't cope with --amend or with squashed
+# commits.
+#
+# The third example adds a Signed-off-by line to the message, that can
+# still be edited.  This is rarely a good idea.
+
+case "$2,$3" in
+  merge,)
+    perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;;
+
+# ,|template,)
+#   perl -i.bak -pe '
+#      print "\n" . `git diff --cached --name-status -r`
+#	 if /^#/ && $first++ == 0' "$1" ;;
+
+  *) ;;
+esac
+
+# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
+# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
@@ -0,0 +1,128 @@
+#!/bin/sh
+#
+# An example hook script to blocks unannotated tags from entering.
+# Called by git-receive-pack with arguments: refname sha1-old sha1-new
+#
+# To enable this hook, rename this file to "update".
+#
+# Config
+# ------
+# hooks.allowunannotated
+#   This boolean sets whether unannotated tags will be allowed into the
+#   repository.  By default they won't be.
+# hooks.allowdeletetag
+#   This boolean sets whether deleting tags will be allowed in the
+#   repository.  By default they won't be.
+# hooks.allowmodifytag
+#   This boolean sets whether a tag may be modified after creation. By default
+#   it won't be.
+# hooks.allowdeletebranch
+#   This boolean sets whether deleting branches will be allowed in the
+#   repository.  By default they won't be.
+# hooks.denycreatebranch
+#   This boolean sets whether remotely creating branches will be denied
+#   in the repository.  By default this is allowed.
+#
+
+# --- Command line
+refname="$1"
+oldrev="$2"
+newrev="$3"
+
+# --- Safety check
+if [ -z "$GIT_DIR" ]; then
+	echo "Don't run this script from the command line." >&2
+	echo " (if you want, you could supply GIT_DIR then run" >&2
+	echo "  $0 <ref> <oldrev> <newrev>)" >&2
+	exit 1
+fi
+
+if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
+	echo "Usage: $0 <ref> <oldrev> <newrev>" >&2
+	exit 1
+fi
+
+# --- Config
+allowunannotated=$(git config --bool hooks.allowunannotated)
+allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
+denycreatebranch=$(git config --bool hooks.denycreatebranch)
+allowdeletetag=$(git config --bool hooks.allowdeletetag)
+allowmodifytag=$(git config --bool hooks.allowmodifytag)
+
+# check for no description
+projectdesc=$(sed -e '1q' "$GIT_DIR/description")
+case "$projectdesc" in
+"Unnamed repository"* | "")
+	echo "*** Project description file hasn't been set" >&2
+	exit 1
+	;;
+esac
+
+# --- Check types
+# if $newrev is 0000...0000, it's a commit to delete a ref.
+zero="0000000000000000000000000000000000000000"
+if [ "$newrev" = "$zero" ]; then
+	newrev_type=delete
+else
+	newrev_type=$(git-cat-file -t $newrev)
+fi
+
+case "$refname","$newrev_type" in
+	refs/tags/*,commit)
+		# un-annotated tag
+		short_refname=${refname##refs/tags/}
+		if [ "$allowunannotated" != "true" ]; then
+			echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
+			echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
+			exit 1
+		fi
+		;;
+	refs/tags/*,delete)
+		# delete tag
+		if [ "$allowdeletetag" != "true" ]; then
+			echo "*** Deleting a tag is not allowed in this repository" >&2
+			exit 1
+		fi
+		;;
+	refs/tags/*,tag)
+		# annotated tag
+		if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
+		then
+			echo "*** Tag '$refname' already exists." >&2
+			echo "*** Modifying a tag is not allowed in this repository." >&2
+			exit 1
+		fi
+		;;
+	refs/heads/*,commit)
+		# branch
+		if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
+			echo "*** Creating a branch is not allowed in this repository" >&2
+			exit 1
+		fi
+		;;
+	refs/heads/*,delete)
+		# delete branch
+		if [ "$allowdeletebranch" != "true" ]; then
+			echo "*** Deleting a branch is not allowed in this repository" >&2
+			exit 1
+		fi
+		;;
+	refs/remotes/*,commit)
+		# tracking branch
+		;;
+	refs/remotes/*,delete)
+		# delete tracking branch
+		if [ "$allowdeletebranch" != "true" ]; then
+			echo "*** Deleting a tracking branch is not allowed in this repository" >&2
+			exit 1
+		fi
+		;;
+	*)
+		# Anything else (is there anything else?)
+		echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
+		exit 1
+		;;
+esac
+
+# --- Finished
+exit 0
@@ -0,0 +1,6 @@
+# git-ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
@@ -0,0 +1 @@
+ref: refs/heads/master
@@ -0,0 +1,7 @@
+[core]
+	repositoryformatversion = 0
+	filemode = true
+	bare = true
+	sharedrepository = 1
+[receive]
+	denyNonFastforwards = true
@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.
@@ -0,0 +1,15 @@
+#!/bin/sh
+#
+# An example hook script to check the commit log message taken by
+# applypatch from an e-mail message.
+#
+# The hook should exit with non-zero status after issuing an
+# appropriate message if it wants to stop the commit.  The hook is
+# allowed to edit the commit message file.
+#
+# To enable this hook, rename this file to "applypatch-msg".
+
+. git-sh-setup
+test -x "$GIT_DIR/hooks/commit-msg" &&
+	exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"}
+:
@@ -0,0 +1,24 @@
+#!/bin/sh
+#
+# An example hook script to check the commit log message.
+# Called by git-commit with one argument, the name of the file
+# that has the commit message.  The hook should exit with non-zero
+# status after issuing an appropriate message if it wants to stop the
+# commit.  The hook is allowed to edit the commit message file.
+#
+# To enable this hook, rename this file to "commit-msg".
+
+# Uncomment the below to add a Signed-off-by line to the message.
+# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
+# hook is more suited to it.
+#
+# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
+# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
+
+# This example catches duplicate Signed-off-by lines.
+
+test "" = "$(grep '^Signed-off-by: ' "$1" |
+	 sort | uniq -c | sed -e '/^[ 	]*1[ 	]/d')" || {
+	echo >&2 Duplicate Signed-off-by lines.
+	exit 1
+}
@@ -0,0 +1,8 @@
+#!/bin/sh
+#
+# An example hook script that is called after a successful
+# commit is made.
+#
+# To enable this hook, rename this file to "post-commit".
+
+: Nothing
@@ -0,0 +1,15 @@
+#!/bin/sh
+#
+# An example hook script for the "post-receive" event.
+#
+# The "post-receive" script is run after receive-pack has accepted a pack
+# and the repository has been updated.  It is passed arguments in through
+# stdin in the form
+#  <oldrev> <newrev> <refname>
+# For example:
+#  aa453216d1b3e49e7f6f98441fa56946ddcd6a20 68f7abf4e6f922807889f52bc043ecd31b79f814 refs/heads/master
+#
+# see contrib/hooks/ for a sample, or uncomment the next line and
+# rename the file to "post-receive".
+
+#. /usr/share/doc/git-core/contrib/hooks/post-receive-email
@@ -0,0 +1,8 @@
+#!/bin/sh
+#
+# An example hook script to prepare a packed repository for use over
+# dumb transports.
+#
+# To enable this hook, rename this file to "post-update".
+
+exec git-update-server-info
@@ -0,0 +1,14 @@
+#!/bin/sh
+#
+# An example hook script to verify what is about to be committed
+# by applypatch from an e-mail message.
+#
+# The hook should exit with non-zero status after issuing an
+# appropriate message if it wants to stop the commit.
+#
+# To enable this hook, rename this file to "pre-applypatch".
+
+. git-sh-setup
+test -x "$GIT_DIR/hooks/pre-commit" &&
+	exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"}
+:
@@ -0,0 +1,46 @@
+#!/bin/sh
+#
+# An example hook script to verify what is about to be committed.
+# Called by git-commit with no arguments.  The hook should
+# exit with non-zero status after issuing an appropriate message if
+# it wants to stop the commit.
+#
+# To enable this hook, rename this file to "pre-commit".
+
+if git-rev-parse --verify HEAD >/dev/null 2>&1
+then
+	against=HEAD
+else
+	# Initial commit: diff against an empty tree object
+	against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
+fi
+
+# If you want to allow non-ascii filenames set this variable to true.
+allownonascii=$(git config hooks.allownonascii)
+
+# Cross platform projects tend to avoid non-ascii filenames; prevent
+# them from being added to the repository. We exploit the fact that the
+# printable range starts at the space character and ends with tilde.
+if [ "$allownonascii" != "true" ] &&
+	# Note that the use of brackets around a tr range is ok here, (it's
+	# even required, for portability to Solaris 10's /usr/bin/tr), since
+	# the square bracket bytes happen to fall in the designated range.
+	test "$(git diff --cached --name-only --diff-filter=A -z $against |
+	  LC_ALL=C tr -d '[ -~]\0')"
+then
+	echo "Error: Attempt to add a non-ascii file name."
+	echo
+	echo "This can cause problems if you want to work"
+	echo "with people on other platforms."
+	echo
+	echo "To be portable it is advisable to rename the file ..."
+	echo
+	echo "If you know what you are doing you can disable this"
+	echo "check using:"
+	echo
+	echo "  git config hooks.allownonascii true"
+	echo
+	exit 1
+fi
+
+exec git diff-index --check --cached $against --
@@ -0,0 +1,169 @@
+#!/bin/sh
+#
+# Copyright (c) 2006, 2008 Junio C Hamano
+#
+# The "pre-rebase" hook is run just before "git-rebase" starts doing
+# its job, and can prevent the command from running by exiting with
+# non-zero status.
+#
+# The hook is called with the following parameters:
+#
+# $1 -- the upstream the series was forked from.
+# $2 -- the branch being rebased (or empty when rebasing the current branch).
+#
+# This sample shows how to prevent topic branches that are already
+# merged to 'next' branch from getting rebased, because allowing it
+# would result in rebasing already published history.
+
+publish=next
+basebranch="$1"
+if test "$#" = 2
+then
+	topic="refs/heads/$2"
+else
+	topic=`git symbolic-ref HEAD` ||
+	exit 0 ;# we do not interrupt rebasing detached HEAD
+fi
+
+case "$topic" in
+refs/heads/??/*)
+	;;
+*)
+	exit 0 ;# we do not interrupt others.
+	;;
+esac
+
+# Now we are dealing with a topic branch being rebased
+# on top of master.  Is it OK to rebase it?
+
+# Does the topic really exist?
+git show-ref -q "$topic" || {
+	echo >&2 "No such branch $topic"
+	exit 1
+}
+
+# Is topic fully merged to master?
+not_in_master=`git-rev-list --pretty=oneline ^master "$topic"`
+if test -z "$not_in_master"
+then
+	echo >&2 "$topic is fully merged to master; better remove it."
+	exit 1 ;# we could allow it, but there is no point.
+fi
+
+# Is topic ever merged to next?  If so you should not be rebasing it.
+only_next_1=`git-rev-list ^master "^$topic" ${publish} | sort`
+only_next_2=`git-rev-list ^master           ${publish} | sort`
+if test "$only_next_1" = "$only_next_2"
+then
+	not_in_topic=`git-rev-list "^$topic" master`
+	if test -z "$not_in_topic"
+	then
+		echo >&2 "$topic is already up-to-date with master"
+		exit 1 ;# we could allow it, but there is no point.
+	else
+		exit 0
+	fi
+else
+	not_in_next=`git-rev-list --pretty=oneline ^${publish} "$topic"`
+	perl -e '
+		my $topic = $ARGV[0];
+		my $msg = "* $topic has commits already merged to public branch:\n";
+		my (%not_in_next) = map {
+			/^([0-9a-f]+) /;
+			($1 => 1);
+		} split(/\n/, $ARGV[1]);
+		for my $elem (map {
+				/^([0-9a-f]+) (.*)$/;
+				[$1 => $2];
+			} split(/\n/, $ARGV[2])) {
+			if (!exists $not_in_next{$elem->[0]}) {
+				if ($msg) {
+					print STDERR $msg;
+					undef $msg;
+				}
+				print STDERR " $elem->[1]\n";
+			}
+		}
+	' "$topic" "$not_in_next" "$not_in_master"
+	exit 1
+fi
+
+exit 0
+
+################################################################
+
+This sample hook safeguards topic branches that have been
+published from being rewound.
+
+The workflow assumed here is:
+
+ * Once a topic branch forks from "master", "master" is never
+   merged into it again (either directly or indirectly).
+
+ * Once a topic branch is fully cooked and merged into "master",
+   it is deleted.  If you need to build on top of it to correct
+   earlier mistakes, a new topic branch is created by forking at
+   the tip of the "master".  This is not strictly necessary, but
+   it makes it easier to keep your history simple.
+
+ * Whenever you need to test or publish your changes to topic
+   branches, merge them into "next" branch.
+
+The script, being an example, hardcodes the publish branch name
+to be "next", but it is trivial to make it configurable via
+$GIT_DIR/config mechanism.
+
+With this workflow, you would want to know:
+
+(1) ... if a topic branch has ever been merged to "next".  Young
+    topic branches can have stupid mistakes you would rather
+    clean up before publishing, and things that have not been
+    merged into other branches can be easily rebased without
+    affecting other people.  But once it is published, you would
+    not want to rewind it.
+
+(2) ... if a topic branch has been fully merged to "master".
+    Then you can delete it.  More importantly, you should not
+    build on top of it -- other people may already want to
+    change things related to the topic as patches against your
+    "master", so if you need further changes, it is better to
+    fork the topic (perhaps with the same name) afresh from the
+    tip of "master".
+
+Let's look at this example:
+
+		   o---o---o---o---o---o---o---o---o---o "next"
+		  /       /           /           /
+		 /   a---a---b A     /           /
+		/   /               /           /
+	       /   /   c---c---c---c B         /
+	      /   /   /             \         /
+	     /   /   /   b---b C     \       /
+	    /   /   /   /             \     /
+    ---o---o---o---o---o---o---o---o---o---o---o "master"
+
+
+A, B and C are topic branches.
+
+ * A has one fix since it was merged up to "next".
+
+ * B has finished.  It has been fully merged up to "master" and "next",
+   and is ready to be deleted.
+
+ * C has not merged to "next" at all.
+
+We would want to allow C to be rebased, refuse A, and encourage
+B to be deleted.
+
+To compute (1):
+
+	git-rev-list ^master ^topic next
+	git-rev-list ^master        next
+
+	if these match, topic has not merged in next at all.
+
+To compute (2):
+
+	git-rev-list master..topic
+
+	if this is empty, it is fully merged to "master".
@@ -0,0 +1,36 @@
+#!/bin/sh
+#
+# An example hook script to prepare the commit log message.
+# Called by git-commit with the name of the file that has the
+# commit message, followed by the description of the commit
+# message's source.  The hook's purpose is to edit the commit
+# message file.  If the hook fails with a non-zero status,
+# the commit is aborted.
+#
+# To enable this hook, rename this file to "prepare-commit-msg".
+
+# This hook includes three examples.  The first comments out the
+# "Conflicts:" part of a merge commit.
+#
+# The second includes the output of "git diff --name-status -r"
+# into the message, just before the "git status" output.  It is
+# commented because it doesn't cope with --amend or with squashed
+# commits.
+#
+# The third example adds a Signed-off-by line to the message, that can
+# still be edited.  This is rarely a good idea.
+
+case "$2,$3" in
+  merge,)
+    perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;;
+
+# ,|template,)
+#   perl -i.bak -pe '
+#      print "\n" . `git diff --cached --name-status -r`
+#	 if /^#/ && $first++ == 0' "$1" ;;
+
+  *) ;;
+esac
+
+# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
+# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
@@ -0,0 +1,128 @@
+#!/bin/sh
+#
+# An example hook script to blocks unannotated tags from entering.
+# Called by git-receive-pack with arguments: refname sha1-old sha1-new
+#
+# To enable this hook, rename this file to "update".
+#
+# Config
+# ------
+# hooks.allowunannotated
+#   This boolean sets whether unannotated tags will be allowed into the
+#   repository.  By default they won't be.
+# hooks.allowdeletetag
+#   This boolean sets whether deleting tags will be allowed in the
+#   repository.  By default they won't be.
+# hooks.allowmodifytag
+#   This boolean sets whether a tag may be modified after creation. By default
+#   it won't be.
+# hooks.allowdeletebranch
+#   This boolean sets whether deleting branches will be allowed in the
+#   repository.  By default they won't be.
+# hooks.denycreatebranch
+#   This boolean sets whether remotely creating branches will be denied
+#   in the repository.  By default this is allowed.
+#
+
+# --- Command line
+refname="$1"
+oldrev="$2"
+newrev="$3"
+
+# --- Safety check
+if [ -z "$GIT_DIR" ]; then
+	echo "Don't run this script from the command line." >&2
+	echo " (if you want, you could supply GIT_DIR then run" >&2
+	echo "  $0 <ref> <oldrev> <newrev>)" >&2
+	exit 1
+fi
+
+if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
+	echo "Usage: $0 <ref> <oldrev> <newrev>" >&2
+	exit 1
+fi
+
+# --- Config
+allowunannotated=$(git config --bool hooks.allowunannotated)
+allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
+denycreatebranch=$(git config --bool hooks.denycreatebranch)
+allowdeletetag=$(git config --bool hooks.allowdeletetag)
+allowmodifytag=$(git config --bool hooks.allowmodifytag)
+
+# check for no description
+projectdesc=$(sed -e '1q' "$GIT_DIR/description")
+case "$projectdesc" in
+"Unnamed repository"* | "")
+	echo "*** Project description file hasn't been set" >&2
+	exit 1
+	;;
+esac
+
+# --- Check types
+# if $newrev is 0000...0000, it's a commit to delete a ref.
+zero="0000000000000000000000000000000000000000"
+if [ "$newrev" = "$zero" ]; then
+	newrev_type=delete
+else
+	newrev_type=$(git-cat-file -t $newrev)
+fi
+
+case "$refname","$newrev_type" in
+	refs/tags/*,commit)
+		# un-annotated tag
+		short_refname=${refname##refs/tags/}
+		if [ "$allowunannotated" != "true" ]; then
+			echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
+			echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
+			exit 1
+		fi
+		;;
+	refs/tags/*,delete)
+		# delete tag
+		if [ "$allowdeletetag" != "true" ]; then
+			echo "*** Deleting a tag is not allowed in this repository" >&2
+			exit 1
+		fi
+		;;
+	refs/tags/*,tag)
+		# annotated tag
+		if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
+		then
+			echo "*** Tag '$refname' already exists." >&2
+			echo "*** Modifying a tag is not allowed in this repository." >&2
+			exit 1
+		fi
+		;;
+	refs/heads/*,commit)
+		# branch
+		if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
+			echo "*** Creating a branch is not allowed in this repository" >&2
+			exit 1
+		fi
+		;;
+	refs/heads/*,delete)
+		# delete branch
+		if [ "$allowdeletebranch" != "true" ]; then
+			echo "*** Deleting a branch is not allowed in this repository" >&2
+			exit 1
+		fi
+		;;
+	refs/remotes/*,commit)
+		# tracking branch
+		;;
+	refs/remotes/*,delete)
+		# delete tracking branch
+		if [ "$allowdeletebranch" != "true" ]; then
+			echo "*** Deleting a tracking branch is not allowed in this repository" >&2
+			exit 1
+		fi
+		;;
+	*)
+		# Anything else (is there anything else?)
+		echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
+		exit 1
+		;;
+esac
+
+# --- Finished
+exit 0
@@ -0,0 +1,6 @@
+# git-ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
diff --git a/var/tmp/source/BROQ/Gitalist-0.002007/Gitalist-0.002007/t/lib/repositories/recursive/nothinginhere/emptyfile b/var/tmp/source/BROQ/Gitalist-0.002007/Gitalist-0.002007/t/lib/repositories/recursive/nothinginhere/emptyfile
new file mode 100644
index 00000000..e69de29b
@@ -1,6 +1,6 @@
 use FindBin qw/$Bin/;
 BEGIN {
-    my $env = "$FindBin::Bin/script/env";
+    my $env = "$FindBin::Bin/../script/env";
     if (-r $env) {
         do $env or die $@;
     }
@@ -95,7 +95,7 @@ throws_ok { Gitalist::Model::CollectionOfRepos->COMPONENT($ctx_gen->(), { repos
 
 {
     my $i = test_with_config({ repo_dir => "$FindBin::Bin/lib/repositories"});
-    is scalar($i->repositories->flatten), 3, 'Found 3 repos';
+    is scalar($i->repositories->flatten), 5, 'Found 5 repos';
 }
 
 {
@@ -1,7 +1,7 @@
 #!/usr/bin/env perl
 use FindBin qw/$Bin/;
 BEGIN {
-    my $env = "$FindBin::Bin/script/env";
+    my $env = "$FindBin::Bin/../script/env";
     if (-r $env) {
         do $env or die $@;
     }
@@ -1,7 +1,7 @@
 #!/usr/bin/env perl
 use FindBin qw/$Bin/;
 BEGIN {
-    my $env = "$FindBin::Bin/script/env";
+    my $env = "$FindBin::Bin/../script/env";
     if (-r $env) {
         do $env or die $@;
     }
@@ -1,6 +1,6 @@
 use FindBin qw/$Bin/;
 BEGIN {
-    my $env = "$FindBin::Bin/script/env";
+    my $env = "$FindBin::Bin/../script/env";
     if (-r $env) {
         do $env or die $@;
     }
@@ -1,6 +1,6 @@
 use FindBin qw/$Bin/;
 BEGIN {
-    my $env = "$FindBin::Bin/script/env";
+    my $env = "$FindBin::Bin/../script/env";
     if (-r $env) {
         do $env or die $@;
     }